大家好 👋,我是 Moment,目前正在使用 Next.js、NestJS、LangChain 开发 DocFlow。这是一个面向 AI 场景的协同文档平台,集成了基于
Tiptap的富文本编辑、NestJS后端服务、实时协作与智能化工作流等核心模块。在这个项目的持续打磨过程中,我积累了不少实战经验,不只是
Tiptap的深度定制、编辑器性能优化和协同方案设计,也包括前端工程化建设、React 源码理解以及复杂项目架构实践。如果你对 AI 全栈开发、文档编辑器、前端工程化或者 React 源码相关内容感兴趣,欢迎添加我的微信
yunmz777一起交流。觉得项目还不错的话,也欢迎给 DocFlow 点个 star ⭐
最近我给一些前端方向的实习生做内推,看了不少简历。投递里常能看出一种预设,找实习只要把前端做熟,页面和接口能啃下来,似乎就踩对了主线。初筛读多了会有另一种感受,当业务和岗位已经大量贴上大模型、RAG 或 Agent 时,纯前端技术栈写得再工整,也很难在一叠写法雷同的简历里单独把人托起来。
我想写的不是简历技巧,评审更常问的是,你有没有把智能接进一条可维护、可观测、也能和人协作的链路,还是只在项目名里多写几个关键词。
许多项目经历段落,技术名词很全,叙事却薄。写得多的几种模式是:
- 周期很短,却同时堆上
RAG、流式输出、鉴权与复杂治理,读者很难估计真实投入与掌握深度 - 段落像功能清单,缺少场景、难点、个人职责与可验证结果,性能数字也缺少口径与复现方式
- 形态集中在教程型对话台或后台管理,技术栈高度同质,差异化不明显
Agent被写成调模型、接工具,很少触及运行时、状态机、评测、观测与人在回路
还有一种写法,整段都在堆大家简历里常见的工程项,例如 JWT、双 token、RBAC、请求拦截器、SSE 或 WebSocket 流式、分片上传、虚拟列表。十条里七八条读起来像同一篇教程拆出来的,名词齐了,却看不出你解决的是哪一道别人没写清楚的难题。基本功当然要会,可若差异化只停在这一层,筛简历的人很难把你从同质化描述里拎出来。
简历上的项目经历一撞脸,筛简历的人就只好盯你有没有把系统做实。后面我按层写。
这两年简历里写 Agent 的人越来越多,细看实现却常常撞脸,核心路径几乎总是同一条。
接收用户输入,调用大模型,解析工具调用,执行工具,返回结果。
引用里那几步,无非是调模型、解析工具调用、执行、再把结果塞回模型。脚手架和跟练多了,半天跑通一个 Demo 很常见。评审里想听的,往往是上线以后要应付的那些事,超时、重试、成本、人要确认、出了事故怎么查和改,你有没有提前铺过路。
面试里真正该往下问的,早就不该是这种技能清单:
- 你会不会调
LLM - 你会不会接
Tool - 你会不会用
LangChain
而是更底层的这个问题:
你有没有把 Agent 当成一个系统,而不是一个函数调用?
能讲清楚这一句,面试官才会继续往下问。落地时大家会盯这几件事有没有做实,有没有进真实产品而不是停在演示分支:
- 有没有独立的
Agent Runtime - 有没有显式状态机驱动的
Agent Loop - 有没有把评测做成回归闸门
- 有没有把观测、检测、红队、安全、成本和用户干预整成闭环
- 能不能把这些能力真正接进产品,而不是停留在一段演示代码
缺了这些,名字再响亮,多半仍是一个带工具调用的聊天接口。本文不写怎么接 OpenAI、怎么声明 Tool,只写骨架。
从 Demo 到产品,Agent 系统到底还差哪几层骨架。
下面按层拆开说明。
为什么很多 Agent 项目能跑,但没有技术区分度
很多人会以为把大模型、多轮、Tool、Memory 和 RAG 勾齐,项目就算做完了。那点东西多半只盖住 demo 里的顺利路径,一遇到真实流量,缺的是运行时、安全、观测和评测这一整圈骨架,而不是再多接一个模型。
它们看起来像 Agent,实际上更像一个带工具调用的聊天接口。
一放量,问题会先挤在几块地方,很少单靠改一段 Prompt 就能压住:
- 同一类提问有时成有时败,工具忽对忽错
- 用户只看到转圈,不知道卡在推理还是在等工具
- 线上成功率掉了,分不清是模型、工具还是外部
API Prompt改完自测像变聪明,线上指标却掉头- 偏航多步也没有让人半途介入的口子
token和钱烧在哪些步骤,心里没底
根本原因多半不在 Prompt 花不花或 Tool 多不多,而在下面几块是否长期空白:运行时、状态机、可观测、评测、风险、HITL、Streaming、成本、异常和线上告警。填不全,项目就会一直像在交课堂作业。只会用 LangChain 也不等于会做 Agent,框架主要管编排,编排以外的那一圈才是评审想听你讲清楚的。
前端加 LangChain 开发者的真正优势
前端背景再叠上 LangChain、LangGraph、工具与记忆,常被低估。和算法岗比的不是论文厚度,而是能不能把智能体做成别人能长期点着用的产品。
你更占便宜的地方,是把
Agent做成用户看得见、停得下来、出了问题能对上账的系统。
模型只是其中一个节点。好不好用还要看,现在在干什么、为什么选这个工具、失败怎么补、用户能不能打断、高风险要不要确认、耗时和钱能不能对上账、改完 Prompt 有没有回归、输出能不能验、输入和工具参数有没有护栏、线上有没有告警。这些早就不是单次推理,而是一整条链路的工程活。状态、异步、中间态、确认、埋点和展示,本来就是前端日常,这块你会比只写脚本的人更顺手。
介绍自己时不必缩成会接某家 API 的前端,可以收成一句实在话。
我负责把
LLM编排、工具、状态机、可观测、评测和交互收成一条,给人用的是产品不是脚本。
交付物也更该像任务控制台,把推理、调工具、等确认、报错恢复这些阶段摊开,而不是聊天框里一条接一条的气泡。
把 Agent 理解成运行中的系统而不是调用链
先把问题问清楚,这东西在产线里更像一次短请求,还是像一趟要跑很久的任务。
不要把 Agent 理解为一次请求的处理流程,而要把它理解为一个持续运行的任务系统。
普通接口大约四步,请求进来,处理完就结束。Agent 更像长跑任务,中间状态多。下图是一条典型阶段划分,提醒自己别再用短接口的思维去估长任务。
图的意思很直白,Agent 更接近任务引擎,而不是只吐一段字的接口。接下来这些问题躲不掉,状态放哪、刷新后怎么续、工具超时重试还是交给人、高风险要不要审批、token 快顶了还跑不跑、工具能不能并行、连走几步没进展算不算打转。这些都算系统设计,不是多写两行 Prompt 能糊过去的。
一个有区分度的 Agent 系统应有的分层
聊 Agent 如果只停在调模型、调工具,听起来总像缺一块。动手前最好先想清楚,界面交互、流程编排、运行时控制、安全治理、可观测和评测各自归谁管,别全糊进一条链。
对外说法可以很简单,Agent 像一条流水线:
用户输入 → 模型推理 → 调用工具 → 返回结果
真要拆职责,可以收成六层:
- 交互层:用户看得见、点得着的界面,负责步骤展示、审批、中断、重试和结果反馈
- 编排层:用
LangChain、LangGraph等把 Prompt、模型、工具、记忆和状态流转组织成可维护的流程 - 运行时 Harness:管理步数、超时、预算、快照、重试、取消和收尾,决定任务如何真正跑完或安全停下
- 安全与检测层:在输入、工具执行前、输出和轨迹上做规则与模型检测,拦住不该发生的行为
- 可观测层:用 Trace、Metrics、日志把每一步变成可查询、可对比、可回放的事实
- 评测层:通过离线集、回归闸门和线上灰度,用数据判断一次改动到底有没有变好
编排层按意图出计划和工具调用,运行时层在预算、超时和状态约束下执行。执行中安全层可能拦截或要审批,可观测层记全程,评测层再拿这些记录去约束下一版 Prompt、节点、工具和发版节奏。
分层不是为了把图画复杂,而是别把运行时、安全、回放、评测和灰度都指望 LangChain 自动搞定。框架主要管编排,编排外那一圈才决定工程含量。
用户意图从交互层进编排层,编排层再把可执行步骤交给运行时。
运行时不只是把流程跑完,还要在执行过程中持续接入安全检测和可观测能力。
可观测记录下来的事实,会进入评测体系,再反向约束下一轮编排和发布策略。
每层用一句话带过,细节可以另写。
交互层负责摊开给人看、给人控。过程可见、风险写操作前要确认、能中断和改向,这些要和运行时对齐,别事后在文案里补两行提示。
编排层用 Prompt、Tool、Memory、图或链把节点串起来。LangChain 一类框架主要管这一层,观测、中断、预算、版本和 bad case 回流多半在编排之外,别把欠账算在框架头上。
运行时层用 Harness 钉死步数、单步和整体超时、token 和墙钟预算、取消和收尾。结束由状态和 Harness 判定,预算触顶该降级就降级,别指望模型自己说做完了。
安全与检测要盖住输入、工具执行前、输出和轨迹。模型吐出来的 tool call 只是草稿,执行前要走白名单、schema、权限和风险分级,高危路径该审批就审批。
可观测层靠 Trace、分层指标和结构化日志,把一次任务从猜变成查,后面才好做归因、回放和调参。
评测层用离线用例、回归闸门和线上灰度回答有没有变好。Prompt、模型、工具或状态机一动,就该自动对比基线,线上反馈要能回灌进用例集。
六层都沾到,才像能交给别人托管的产品,而不是只证明链路能跑通的 Demo。
Agent Loop 应该是显式状态机而不是 while 循环
最朴素的 Agent Loop 是反复调模型、判断是否调工具、拿结果再回模型,直到产出答案。这个流程能跑通,但一进真实场景就容易失控,因为很多关键分支塞不进一个裸 while 循环。
真正容易栽跟头的几件事:
- 工具失败后的重试与止损
- 高风险动作前的人工确认
- 预算触顶后的降级与收尾
- 上下文过长时的压缩与续跑
- 用户中断后的恢复与回放
把 Loop 收成显式状态机,让系统在 Reasoning、ToolSelecting、Executing、AwaitingConfirmation、Recovering、Finalizing 等状态之间按条件跳转,分支写在表里,比藏在 if 里好查也好测。
状态机写清楚以后,日常会顺很多。状态一眼能看见,分支不再散在 if 里,前后端对得上号,暂停、恢复、撤销、重试也好接。
把它和前面的 AgentHarness 组合后,职责会更清晰:
Harness负责时间、步数、token、取消和强制收尾- 状态机负责业务语义、路径选择和异常分支
上线以后,Loop 往往还要挂审批、检测、回滚、埋点和评测,能挂在状态切换点上就别散在业务代码里。
收个尾,Agent Loop 不该只是会转的循环,最好收成一台可解释、可干预、可恢复、也能审计的状态机。
把人设计进系统而不是把人当兜底
很多团队把 HITL 理解成出错后的兜底,这会让人机协同长期停在救火阶段。设计阶段就把哪些动作自动放行、哪些必须确认、哪些默认拒绝写清楚,比上线后救火省事。
HITL是Human-in-the-loop,意思是把人放进关键决策回路。系统负责执行与提议,人负责在高风险节点确认、纠偏和兜底。
风险分级可以先从三档起步,阈值和白名单由业务与合规共同维护:
- 低风险,默认自动执行,失败后可重试或降级,例如搜索文档、读取代码、查询只读数据、整理摘要
- 中风险,可自动执行但要留痕,并保留撤销窗口,例如文案修改、批量替换、工作区文件编辑
- 高风险,执行前必须阻断并等待确认,例如删除文件、外网请求、代码提交、数据库变更、发布和付费接口调用
差别通常不在有没有确认按钮,而在卡片里给不给够决策信息。动作是什么、为什么动、影响范围、能不能撤销、有没有备选,最好一眼能看完,别只剩一句是否继续。
审批如果只在前端拼文案,很快会和真实执行脱节。更省事的做法是把审批收成结构化数据,从后端下发,挂到同一条 trace 上,事件流里推 approval_required,回放、审计和告警都读同一份。
卡片上最好有:
- 风险等级、审批时限、发起来源一眼可见
- 受影响资源和变更范围可展开查看,必要时接
Diff - 可逆操作提供
Undo入口和预计回滚成本 - 支持改参数或切换替代动作后再执行,减少往返沟通
- 全量记录审批人、审批理由、执行结果,满足审计留痕
审批、trace、状态机和观测如果能共用一套模型,人机协同就不只是打补丁。
Streaming 应该让 Agent 过程可见
流式输出如果只用来更快吐 token,对 Agent 任务帮助有限。用户更想知道现在卡在哪一步、工具在干什么、要不要自己点一下。
事件可以粗分三类,最好走同一条推送通道,省得前端接好几套协议:
token层,持续输出自然语言内容step层,推送每一步的动作、工具状态和中间结论progress层,推送总进度、耗时和成本,减少等待焦虑
用一条联合类型把字段钉死,前后端少扯皮。下面是个示意,覆盖状态变化、工具起止、审批、进度和收尾,载体可以用 WebSocket 或 EventSource。
type AgentStreamEvent =
| { type: "state_changed"; state: AgentState; at: number }
| { type: "token"; text: string; stepId: string }
| { type: "tool_started"; stepId: string; tool: string; args: unknown }
| { type: "tool_finished"; stepId: string; ok: boolean; summary: string }
| { type: "approval_required"; request: ApprovalRequest }
| { type: "progress"; done: number; total: number; costUsd: number }
| { type: "final"; answer: string; traceId: string }
| { type: "error"; message: string; recoverable: boolean };
协议统一以后,时间线、步骤卡片、进度条和审批弹窗才好做,中间态不必全塞进气泡里。界面上比较值得先做的几件事:
- 步骤折叠与展开,避免长任务刷满屏幕
Observation面板分层展示工具入参、结果摘要、原始返回- 工具日志实时滚动,失败步骤高亮并给出重试入口
- 全局状态浮层显示当前状态机节点与等待原因
Stop、Retry、Continue、插话打断与后端取消契约对齐- 人工接管入口用于切换执行策略或直接改写下一步
- 最终答案和中间证据联动,点击引用可回跳对应 step
同样是等三十秒,转圈和看着系统一步步推进,感受差很多。过程可见,用户能更早纠偏,也能少烧不少无效 token。
离线评测资产、线上观测与可迁移遥测
Agent 要长期迭代,既要离线侧能证明有没有变好,也要线上侧能看见真实流量里发生了什么,还要让埋点与字段尽量不因换观测后端而推倒重来。这一节把三件事收进一条工程链条:先固定可迁移遥测语义,再让离线评测与回归产出可进闸门的证据,最后在线上仍用同一套字段读 trace、成本、实验与用户反馈。底座语义与线上观测必须同源,否则灰度里对不上离线报表。
语义底座先把典型 span 名、属性键和事件形状写进约定,常见列包括 trace_id、span_id、model、token 进出与 cost_usd 等,并对齐 GenAI 与 OpenTelemetry 社区里已经有人在用的写法。这样换导出器或换观测后端时,主要改连接与映射,业务代码少动字段名。离线评测与回归靠版本化用例集、对结果与格式与合规的断言、与基线的对照统计、接入 CI 的闸门和可计量的回归耗时,把主观手感压成可复跑的 Eval 分数。线上可观测在同一套定义下读 trace 时间线、成本随时间和用量变化、AB 流量拆分、用户情绪与满意线索、以及告警与异常。工程上的收束是:语义先沉淀进离线证据,离线结论再拿去和线上 trace、金丝雀或灰度放量对齐,团队才不会各写各的报表。
落到工具时,离线侧靠版本化用例、对过程与结果的断言、基线对比和接入 CI 的闸门把手感变成证据。promptfoo、DeepEval、Ragas 分别偏配置、断言、指标,关键是同一套用例能从开发跑到发布。线上噪声更大,盯住任务完成率、工具成功与超时、成本与风险侧信号即可。Langfuse、LangSmith、Phoenix、Helicone 选型看能否把 trace、实验、分数和反馈收进同一面板。OpenTelemetry 的 GenAI 语义适合当公共约定,先统一 LLM、tool、agent 如何建 span,以及 token、延迟、错误码等字段,迁移成本主要在导出器。
前端加 LangChain 开发者可以重点讲的几点
前端把运行中的系统摊开给人看:状态、步骤、工具、风险、中断重试入口,以及 token 与成本摘要。trace 不应只躺在仓库里,而要变成时间线、Step 卡片、风险高亮和失败回放。模型差不多时,把过程讲清楚往往比再换一次模型更能换来信任和效率。
一个成熟 Agent 项目的技术区分度该怎么描述
重点不是接了哪个新模型,而是能否在真实业务里持续跑稳、可对比、可审计。下面是一段自述示例,可按实际情况改名词和程度。
我做的不是调模型、调工具的 Demo,而是面向真实用户的 Agent 运行系统。
LLM与编排负责生成与流转,Harness、状态机 Loop、风险控制、HITL、可观测和评测负责稳定与可治理。 工程上我会打通离线评测、线上观测和回归闸门,用统一遥测语义串起trace、成本、质量与用户反馈,让每次迭代可对比、可回放、可审计。 我有前端背景,会把过程可视化、干预入口和体验指标当成主交付物,而不是只交最后一段文本。
总结
RAG 可以做,Agent 也可以做,它们都只是手段,不是终点。真正拉开差距的是你有没有把需求、执行、观测、评测和迭代接成闭环。下面四条自检,有一半答不上来,就值得对照正文里的分层补一补。
- 执行与韧性:是否有独立运行时与预算约束,
Loop是否显式状态机,故障能否回放,成本与步数是否可解释。 - 质量与证据:是否有维护中的评测集、
CI或合并前的回归闸门,红队用例是否像测试代码一样可复跑,而不是发版前凭手感点几下。 - 安全与过程:输入、工具调用前、输出与轨迹四层里,哪些已经落地成策略与埋点,高风险路径是否默认进审批而不是靠运气不触发。
- 观测与闭环:线上是否能同时看到
trace、成本、实验与用户反馈,离线分数与线上信号能否进同一套界面或同一套数据模型,而不是各团队各一份报表。
能跑通链路只是起点,能不能长期闭环才是标准。
你有没有把它做成一个能稳定运行、可观测、可评测、可干预、还能持续迭代的闭环系统。
走前端加 LangChain 这条线的人,手里正好捏着界面、状态和事件,把这些和模型、工具、观测、评测缝在一起,比单纯多接一个模型更难被模板替代,写进自我介绍里也更有话可说。