
从去年开始我身边越来越多同事的title里出现了FDE三个字母。有人以为这是前端工程师Front-End Developer的缩写也有人觉得是某个新职级。其实在我做的这条业务线里FDE指的是Feature/Full-cycle Development Engineer——从需求定义一路负责到上线反馈的全流程研发工程师。但光有title没用真正让我对FDE这个角色有实感的是在把Agent Harness、Skills、RAG、MCP四样东西全部串进日常开发流程之后。这篇文章不聊概念只讲我从设计到实现的完整实操过程包括选型逻辑、踩坑记录、还有最后跑通全链路的真实效果。1. FDE到底在管什么Agent时代的工作台重构1.1 我理解的FDE不是“会写代码的产品经理”FDE这个角色在国内讨论度突然变高和AI Agent的普及有很大关系。以前一个需求从想法到上线要经过产品、设计、前端、后端、测试、运维好几手。每个人只负责自己那一亩三分地信息在交接中不断损耗。FDE的思路是一个人把需求闭环跑完代码写得模型调得知识库搭得工具链也接得。这不是说要你一个人干十个岗位的活而是要求你具备横向打通的能力。尤其是在Agent开发这个场景里需求方根本分不清“知识库检索不到”到底是数据问题、Embedding模型问题还是Prompt问题。如果你只懂某一层整个链路就会卡死在边界地带。FDE的价值就是当那条把碎片串起来的线。1.2 Agent Harness在FDE工作流中的定位我见过太多团队一上来就调大模型API把所有的编排逻辑都塞进Prompt里。结果Prompt越来越长模型输出越来越不稳定加一个工具就要改一大段提示词。这就是典型的缺少Agent Harness的表现。Harness这个词在AI工程领域里的含义可以简单理解成“给Agent套上的运行框架”。它不是某个具体模型也不是某个单一工具而是负责管理Agent生命周期的一整套机制上下文窗口的组装、工具调用的路由、任务状态的保存、错误恢复策略、多步执行计划都在Harness层解决。如果拿前端做类比模型是“浏览器内核”Harness是“框架层”。你当然可以手写原生JavaScript不依赖框架但当一个页面有几百个交互状态时框架带来的收益是碾压性的。Agent一旦涉及多轮工具调用同样需要一层结构化的“容器”否则就是一场灾难。1.3 一条链路中的四个关键节点我最终跑通的架构可以用一句话概括Harness是大脑的骨架Skills是重复经验的肌肉记忆RAG是长期记忆的外部化MCP是手和脚。Harness负责决策流程决定下一步该做什么Skills把高频操作封装成可复用的动作库RAG提供需要查证的事实和知识MCP负责把Agent和外部系统连接起来。这四个节点缺一不可。没有SkillsAgent每次都要重新“学习”怎么写测试用例没有RAG模型只能靠训练数据里的过时知识硬猜没有MCPAgent再聪明也无法真正操作系统里的工具。2. Agent Harness选型与搭建骨架不能将就2.1 核心组件拆解从Context组装到工具路由我最早调研Harness时看到GitHub上一堆项目都自称Agent Framework但真正落地就会发现有几个组件是必须具备的。第一是上下文组装器。它负责把系统指令、历史对话、检索到的知识片段、当前工具返回的结果按一定策略拼装成模型输入。拼装顺序直接影响模型理解。我的实践经验是最新工具结果放在离问题最近的位置历史对话做压缩摘要知识片段按相关性排序后插入。第二是工具注册表。所有Skills和MCP工具都要在这里登记声明它们的名称、参数Schema、用途描述。模型会根据这些描述决定是否调用。这里有个很多人忽略的细节工具描述写得越像“给同事的工作交接单”模型选对的概率越高。我见过有人把工具描述写成“精美绝伦的高性能函数”完全没说它具体干什么模型直接无视。第三是执行循环管理器。Agent不是一次性生成答案就结束的它需要循环执行“推理-调用工具-观察结果-再推理”这个过程直到任务完成。这个循环不能无限跑所以必须设置最大迭代次数和终止条件。我通常设20轮上限超过就强制收尾并告诉用户哪些步骤没完成。2.2 我选型时的三个硬性标准现在市面上的Harness方案五花八门有轻量的函数库也有重型的可视化平台。我不建议一上来就选最重的那个先看三个硬性标准能否本地跑通完整闭环我不希望调试一个简单流程必须依赖云端服务本地可运行是底线。工具接入是否是声明式每加一个工具都要改核心代码的后期会痛不欲生。执行过程是否可观测Agent每一步在想什么、调用了什么工具、花了多少token必须能导出日志。按这三个标准筛下来我最后选择了基于Python的轻量级框架自建Harness核心代码只有几百行但把上下文组装、工具路由、循环控制都做了模块化。选它的原因很直接可观测性完全可控出了任何问题都能从日志里定位而不是抱着一个黑盒干瞪眼。2.3 自建Harness最容易踩的坑会话状态管理很多自建Harness的项目挂在同一个地方会话状态没有持久化。Agent跑到第三步时调用了工具结果用户刷新了一下页面整个状态全没了又要从头开始跑。这在真实业务里根本无法接受。我当时踩过的坑是把会话状态简单地存在内存字典里结果开两个并发请求就串了。后来改成每个会话一个独立的状态对象所有中间信息——包括已执行的步骤、已获取的工具结果、当前上下文摘要——全部序列化存入数据库。这样即使进程重启Agent也能从断点继续执行。这个改动看起来不起眼但直接决定了Harness能不能上生产。3. Skills机制把“会做的事”沉淀成Agent肌肉记忆3.1 Skills和普通Prompt之间隔着一条“工程化”鸿沟最早我用Prompt模板要求模型按固定格式输出JSON再写代码去解析。这种方法在小规模验证时没问题但一旦需要复用问题就来了同一个能力在A项目里的Prompt和B项目里的Prompt几乎一样却无法共享模型偶尔输出格式错误解析代码就崩。Skills机制的思路完全不同。它把“写测试用例”“做Code Review”“生成数据库迁移脚本”这些能力封装成独立的模块。每个模块包含专用的Prompt片段、输入输出Schema、后处理验证逻辑和示例样本。模型调用Skill时不是靠记忆里的模糊印象自由发挥而是按照一套标准化流程执行。这个过程可以类比为老工程师把经验固化成函数库。你不需要每次回忆“测试用例到底要覆盖哪些场景”直接调用这个Skill里面的Prompt和校验逻辑会确保输出质量。3.2 前端开发Skills实战从代码审查到样式复测结合我日常做前端重构的实践分享两个我封装后一直在用的Skills。第一个是Code Review Skill。它不是一个简单的“帮我看看代码有没有问题”而是拆成四条检查线逻辑正确性、可维护性、性能隐患、可访问性。每条检查线都有独立的检查清单模型执行时逐条核对最后按优先级输出问题列表。实测下来这个Skill比直接问“这段代码怎么样”的输出结构清晰得多而且不会漏掉低优先级的问题。第二个是视觉还原度Skill。前端开发里最烦的就是设计和实现有偏差。这个Skill的流程是接收截图和设计稿先描述两者差异再列出需要调整的CSS属性最后给出修改建议。配合Playwright MCP抓取页面截图这个Skill可以把大部分样式问题自动过一遍。虽然不能完全替代设计师的人工确认但至少能筛掉80%的明显偏差。3.3 Skills测试与版本管理像对待代码一样对待SkillsSkills本质上也是代码资产所以必须纳入版本管理。我的做法是每个Skill都有独立仓库包含三个部分SKILL.md描述用途和参数prompt/目录存放不同阶段的Prompt片段tests/目录存放测试用例。测试Skills的方法也很有讲究。我会准备一批“黄金输入”即历史上效果最好、最典型的输入样本。在每次修改Skill之后用这批黄金输入跑一遍输出和预期结果对比。如果某个改动让之前的正确结果变差了说明这个Skill发生了回归。这个机制虽然简单但在多次迭代后效率提升立竿见影不然改一次坏一次都不知道。另一个容易被忽略的点是Skill的元信息里要写明依赖关系。我的某个测试用例生成Skill依赖MCP里的数据库查询工具如果在Harness里没注册这个工具Skill会静默失败。现在我会在Skill的配置里显式声明依赖的工具和RAG知识域加载时自动检查环境是否满足。4. RAG知识库接入从“能检索”到“检索得准”4.1 RAG瓶颈为什么搜得到文章却回答不出答案RAG看起来原理很简单把文档切片、向量化、存进向量库用户提问时召回相关片段交给大模型生成答案。但真正跑起来就会发现RAG的瓶颈根本不在于向量检索的召回率而在于三个关键环节切片质量切片太短上下文不完整切片太长又容易混入大量无关内容。我见过有人按固定字符数粗暴切片结果把两个完全不相干的主题切进了同一块检索时噪声极大。召回后的排序和过滤Top-K取多少、相似度阈值设多少、要不要做重排序这些组合直接影响最终喂给模型的内容质量。答案生成时的引用约束如果模型在生成答案时自由发挥没有强制它基于检索片段作答那RAG就和普通对话没有任何区别。我跑通RAG之后回过头看“为什么我的RAG效果差”这个问题十有八九是这三个环节里的某一个出了问题而不是向量数据库选得不对。4.2 知识图谱、RAG和结构化知识库的边界最近很多人问知识图谱KG和RAG到底啥关系。我的理解是RAG擅长回答“某篇文档里怎么说”KG擅长回答“A和B之间的关联是什么”。RAG适合处理非结构化文本——帮助文档、研发Wiki、聊天记录。它检索的是“语义相似的内容片段”。但当你问“哪些服务依赖了这个被废弃的API”这种需要多跳推理的问题时纯RAG会非常吃力因为向量检索只能找到“看起来相关”的片段没有真正理解实体之间的连接关系。这时就需要结构化知识库。我实际的做法是拆成两层一层是传统的知识图谱存放服务依赖、团队归属、系统模块关系这类强结构化数据另一层是向量RAG库存放文档和讨论记录。查询时先判断问题类型——如果是事实查找类走RAG如果是关系推理类先查图谱再用图谱结果去RAG里补充上下文。4.3 在Mac上从零搭一套RAG知识库我在Mac上的搭建方案很轻量全程不需要GPU也能跑。选型是Ollama加载Embedding模型向量库用Chroma再通过LangChain做编排。具体步骤如下先安装Ollama并拉取Embedding模型我用的是nomic-embed-text它在语义相似度上的表现和资源占用比较平衡。brew install ollama ollama pull nomic-embed-text然后安装必要的Python库pip install langchain chromadb langchain-community接下来编写一个简单的索引脚本读取指定目录下的Markdown文档按标题层级和段落进行语义切分再做向量化入库from langchain_community.document_loaders import DirectoryLoader from langchain_community.embeddings import OllamaEmbeddings from langchain.text_splitter import MarkdownHeaderTextSplitter from langchain_community.vectorstores import Chroma loader DirectoryLoader(./docs, glob**/*.md) docs loader.load() headers_to_split_on [ (#, H1), (##, H2), (###, H3), ] splitter MarkdownHeaderTextSplitter(headers_to_split_onheaders_to_split_on) splits [] for doc in docs: splits.extend(splitter.split_text(doc.page_content)) embeddings OllamaEmbeddings(modelnomic-embed-text) vectorstore Chroma.from_documents(splits, embeddings, persist_directory./chroma_db) vectorstore.persist()这里有个关键小技巧用MarkdownHeaderTextSplitter按标题切分而不是按固定长度切分。因为文档的语义边界往往和标题结构高度一致按标题结构切出来的片段内部主题更统一检索效果会好一个档次。4.4 检索调优实测重排序不是可有可无最初我的检索链路是“向量召回Top-10直接塞给模型”效果只能说勉强能用。后来加了重排序层——先用向量召回Top-30再用Cross-Encoder模型对这30条做精细打分选Top-5喂给模型。同样的知识库回答准确率肉眼可见地上升。重排序的原理可以这样理解向量检索是“海选”速度快但粗Cross-Encoder是“终面”把问题和候选片段逐对拼接成完整上下文让模型判断二者是否真正相关。代价是速度慢所以只能让它处理少量候选。实测数据可以参考纯向量召回Top-5的答案命中率大约在60%左右加了一轮重排序后提升到85%以上。对于知识密集型场景这一步的性价比极高。另外一个常见的坑是一味增加Top-K数量。Top-K提上去之后模型容易看到过多内容不知道到底该以哪一段为准输出开始“和稀泥”。我在实践中把最终喂给模型的片段控制在3到5条每条控制在500字内效果最稳定。5. MCP工具层让Agent真正“动手干活”的最后一公里5.1 MCP到底是什么一个标准化的工具插座MCPModel Context Protocol本质上是一套开放协议规定了AI模型如何发现和调用外部工具。它把“工具”抽象成标准化的接口——工具名称、输入参数、输出格式都遵循统一规范。这样一来任何支持MCP的客户端都能无缝接入任意实现了MCP协议的服务端。这就像USB-C口一样。以前Agent接一个浏览器自动化工具要专门写适配代码接一个数据库查询工具又要写另一套适配代码。每个工具一套接口维护成本失控。有了MCP之后很多工具直接暴露成标准MCP服务Harness只需一个通用客户端就能调用全部。我现在的Harness里内置了一个MCP客户端配置一个JSON列表就能注册所有工具。新工具接入从一个“开发任务”变成了一个“配置任务”。这种收益在工具数量超过十个之后特别明显否则每次新增工具都可能引发联动Bug。5.2 从零实现一个MCP服务Java接口快速转接的实战我们团队很多内部系统是老Java REST接口为了把这些接口变成MCP工具我尝试了一条“不重写业务代码”的路径在原有Rest接口外层加一层MCP Adapter。这里给出一个最小Python示例基于官方MCP Python SDKfrom mcp.server.fastmcp import FastMCP mcp FastMCP(legacy-service-bridge) mcp.tool() async def query_issue_status(issue_id: str) - dict: 通过内部接口查询工单状态 import httpx async with httpx.AsyncClient() as client: resp await client.get( fhttp://internal-api/issues/{issue_id}, headers{X-Internal-Token: xxx} ) return resp.json() if __name__ __main__: mcp.run(transportstdio)这段代码做的事情很简单把一个REST接口包装成MCP工具。声明了工具名query_issue_status参数是issue_id返回JSON。Harness里的Agent看到“查询工单状态”这个描述就会自动调用它。这里的核心心得是MCP不要求你把所有工具重写一遍只需要做一层薄的适配层。商务系统的数据库连接方式、内部API的鉴权逻辑都不用动改动量大幅降低。我甚至用一个通用脚本扫描整个项目的REST端点批量生成MCP工具注册信息然后人工审核一遍就上线了。5.3 Playwright MCP自动化从0到1跑通浏览器操作如果你要做前端技能验证、页面回归测试、或者任何需要操作浏览器的场景Playwright MCP是目前我体验最顺的工具之一。它允许Agent通过MCP协议直接控制浏览器打开页面、点击按钮、输入文本、截图、读取控制台日志。我印象最深的一个场景是让Agent自动跑一遍“用户登录-创建项目-修改配置-保存”的完整流程每执行一步都截图发现异常时直接读取网页上的错误信息并定位原因。以前这条链路需要一个前端测试工程师花大半天手写脚本现在用自然语言描述流程即可。接入步骤并不复杂npx playwright/mcplatest --port 8931然后在Harness的MCP客户端配置里加上这个服务地址即可。一个细节是Playwright MCP的浏览器是它自己启动的独立实例和你的日常浏览器不共享Session首次运行需要重新登录被测系统。我一般会让Agent先执行“访问登录页并填写测试账号”步骤来初始化状态。5.4 MCP安全边界权限、审计和熔断工具接入越方便越要重视安全边界。我的原则有三条最小权限MCP服务只声明它确实需要的接口绝不开放给一个宽泛的数据库账号。比如query_issue_status只能查询不支持修改状态。操作审计所有经过MCP的工具调用都要记录日志包含参数、调用者、结果摘要。这在出现问题时能快速回溯是谁执行了什么操作。熔断机制某些工具在Agent陷入循环或被误导时可能会被高频调用。我在MCP适配层加了频率限制和调用总量上限超过阈值直接拒绝避免它把内部系统“打爆”。有一次测试中Agent因为一个参数描述不清晰反复调用删除接口差点把测试数据清空。从那以后所有写操作类工具都默认开启“二次确认”模式——Agent需要先输出计划经过我确认后才真正执行。安全永远比自动化效率更优先。6. 端到端复盘一个真实需求如何串起全链路6.1 需求拆分从用户原话到Agent可执行的任务图以一个我们真实跑过的需求为例用户提出“现有系统的登录流程太慢想看看瓶颈在哪里”。第一步不是写代码而是把这个模糊需求拆成Agent可执行的子任务用Playwright MCP录制一次完整登录流程的耗时分布。从RAG知识库里检索登录服务的历史优化文档和性能基线。调用内部接口获取登录链路的服务依赖图。汇总数据后给出性能分析报告。这些子任务分别依赖不同的工具和知识源Harness负责把它们编排成执行顺序。注意这里有个关键设计不是让Agent一次性并行执行所有任务而是先检索知识库再根据知识库里的历史结论决定要不要跑性能录制。知识指导行动而不是盲目行动。6.2 执行过程中的意外RAG召回和MCP工具之间的协作失败第一次完整跑链路时意外出现在第二步和第三步的衔接处。RAG检索出了一篇很关键的优化方案但里面提到“用MCP调用压测工具查看接口响应时间”而Harness的MCP客户端并没有注册压测工具。Agent给出了一个“有头无尾”的分析报告提到了压测建议但没有实际数据。这个问题的根因是RAG知识库里的内容“超前”于当前工具环境。知识库里写了某种做法但承载该做法的工具没有接入。解决方法是两层一方面要让知识库的维护者定期更新“当前已接入工具清单”另一方面在Harness加载RAG知识时过滤掉其中引用了未注册工具的段落。6.3 效果与教训不要迷信“一键全自动”这条链路跑通后整体效率提升大概在4到5倍。原来一个性能分析需求从沟通、取数、复现到出报告需要1天现在压缩到2小时左右。但我也必须强调一点不要迷信“一键全自动”。实际落地时Harness更像是一个“高度自动化的辅助驾驶”而不是无人驾驶。关键决策点仍然需要人来确认。比如Agent判断“登录慢是因为某个中间件超时配置不合理”这个结论不能直接生效需要人复核后再决定是否修改配置。FDE的核心价值不在于把决策权交给模型而在于为模型设计一条可约束、可追溯的执行路径让它在安全边界内最大化地干活。在我自己的团队里现在新同学上手一个模块时会先要求他们跑一遍完整链路亲手看Harness日志里每一步的决策依据再让他们反思如果自己是模型在这个上下文里会不会选错工具。这种方式比看一百页文档都管用。最后想分享一个小经验Agent Harness、Skills、RAG、MCP不是四件独立的事它们只有组合在一起才能让FDE真正变成一个角色而不是一个头衔。