Agent 执行到一半服务重启了,任务应该怎样恢复?
Agent 故障恢复不能只保存聊天记录。需要持久化任务标识、运行状态、已完成步骤、待处理动作和必要的结果引用,重启后才知道从哪里接着做。恢复时,执行器先取得任务的执行权,再读取最后保存的状态。已确认完成的步骤可以复用结果;
LangChain、LangGraph 等框架的内部机制、适用边界与选型逻辑。用框架,但不被框架用。
共 9 篇文章
Agent 故障恢复不能只保存聊天记录。需要持久化任务标识、运行状态、已完成步骤、待处理动作和必要的结果引用,重启后才知道从哪里接着做。恢复时,执行器先取得任务的执行权,再读取最后保存的状态。已确认完成的步骤可以复用结果;
Agent 调用 MCP 工具时,模型负责提出工具和参数,权限要由可信服务检查,不能让模型判断自己有没有权限。对于需要授权的 HTTP MCP 服务,服务器先验证访问令牌是否有效、是否是签发给自己的,以及是否具备本次请求需要的权限。
这三个选择并不是按“简单、中等、复杂”排成一条线。LangChain 提供比较高层的模型、工具和 Agent 组织方式,它的 Agent 底层使用 LangGraph;LangGraph 则让我们更直接地定义状态、节点和执行路径。
构建 RAG 评测集,我会先确定系统服务哪些人、解决哪些问题,再从脱敏后的真实请求、失败案例和业务人员提供的场景中收集样本。缺少的类型,可以用模型辅助生成。
多 Agent 传递上下文,不应该默认复制全部聊天,也不能只发一句简短任务。应该根据子 Agent 的职责,提供目标、必要背景、共同约束、可用资料和输出要求。例如比较两款软件,一个子 Agent 调查功能,另一个调查部署方式。
Agent 的长期记忆,是把跨会话仍然有用的信息保存下来,并在后续任务需要时取用,不是把所有聊天都永久保存。设计时,我会给记忆记录用户、适用范围、来源、更新时间和有效状态。
Agent 使用 Skill,一般可以分为发现、选择和加载。应用先提供名称、描述等简要信息;模型判断当前任务需要哪些 Skill,再读取对应的完整说明和必要材料。
代码能运行,只能说明它通过了部分检查,不能说明需求已经完成。我会先把需求转成能观察的验收条件。例如导出全部筛选结果,就需要验证跨页数据、筛选条件、字段内容和用户权限,而不只是检查下载按钮能不能点击。
Agent Harness 可以理解为围绕模型搭建的一套运行系统。模型负责根据当前信息做判断,Harness 则负责把需要的信息交给模型、执行允许的工具调用,再把结果送回去。
Agent 的上下文压缩,不能只是把聊天记录缩写一遍。因为后面的执行依赖前面留下的目标、限制、证据和进度,漏掉其中一项,任务就可能走偏。因此,我会先把这些内容分开处理:当前目标和操作限制单独保留;已经完成的过程整理成摘要;
LangChain Middleware 是介入 Agent 执行过程的一组钩子。可以在调用模型前整理输入,也可以包住模型或工具调用,处理重试、路由和提前结束等逻辑。Tool 负责完成具体业务动作,例如搜索资料、查询订单。
LangGraph 子图就是把一个图放进另一个图里,作为其中的一个节点使用。它适合封装可以独立理解和复用的多步流程,例如把搜索、阅读和资料汇总做成一个资料收集子图。父子图怎样传状态,要看它们的接口。
离线评测使用的是准备好的样本,能帮助判断新方案是否值得上线验证,但不能完全代表真实流量。灰度发布会先让一部分用户或会话使用新版本,其余继续使用旧版本,作为同期对照。
Prompt 会影响模型的任务处理、输出格式和工具选择,因此应该像其他程序配置一样管理版本。修改时保留旧内容,形成一个可以准确定位的新版本,再用固定样本和历史错误问题比较效果。测试通过以后,才把生产环境切到新版本,而不是直接覆盖线上文字。
Agent 生成的代码,仍然应该按不可信程序处理。模型可能写错代码,也可能受到用户输入或外部内容影响,所以不能直接让它访问业务服务器的全部资源。沙箱会给代码提供受限制的运行环境。
Agent Skill 通常是一份可复用的任务说明包,里面有适用场景、处理步骤,也可以附带脚本、模板和参考资料。例如,告诉 Agent 写周报时先检查哪些进展,再按什么格式整理。MCP 是 AI 应用连接外部能力的协议。
处理 PDF 表格时,不能只提取文字,还要保留表格的结构。例如“100”这个数字,到底是 100 GB 存储,还是最多 100 个成员,取决于它所在的行和列。解析时需要保存套餐名称、列标题、单位,以及合并单元格、脚注和跨页关系。
父子检索会把检索和回答使用的文本,分成两种粒度。入库时,先保留较完整的父段落,再从里面切出较小的子片段。子片段用来建立检索索引,同时记录自己属于哪个父段落。
LoRA 是一种参数高效微调方法。它保留基础模型已有的权重,在选定的层旁边加入少量可训练参数,用这部分参数学习任务需要的调整。具体来说,原来一个很大的权重改变量,会用两个较小矩阵的乘积来表示。
常见的自回归大模型推理,可以分成 Prefill 和 Decode 两个阶段。Prefill 处理输入内容。例如,我们发给模型一份报告,它需要先计算这段输入对应的表示。输入越长,通常需要处理的工作就越多。
LLM-as-a-Judge 就是让大模型充当评审,根据问题、参考材料和评分标准,对答案打分或比较两个答案哪个更好。它适合检查语义上的问题,比如回答是否符合资料、有没有答到用户关心的内容。
用户点“停止生成”,不代表后端一定停止了。前端中断请求,首先影响的是这条连接;如果任务已经在后台独立运行,它还可能继续调用模型和工具。所以,我会用任务 ID 发起明确的取消请求。
Agent 的工具不是越多越好。工具多了,模型可以处理更多类型的任务,但如果把大量相似的工具定义一次性放进去,也会增加输入长度,让选择变得更容易混淆。
多轮 RAG 不能只拿用户最后一句话去检索,因为“企业版呢”“这个怎么开通”这样的追问,单独看并不完整。一种常见做法是,先结合相关聊天记录,把当前问题补成能够独立理解的检索问题。
Few-shot Prompting 就是在提示词里放入少量“输入和正确输出”的例子,再让大模型处理新的输入。例如,给客服工单分类时,光说“分成故障、使用咨询和功能建议”,模型未必清楚我们的具体标准。
RAG 会在用户提问以后,先检索相关资料,再把资料和问题一起交给大模型。这种做法适合公司制度、产品文档这些需要经常更新、回答时还要说明出处的内容。微调则是在已有模型上继续训练,调整可训练的参数,改善特定任务上的表现。
排行榜可以先看,它能帮我们找几个值得试的模型。但最后选谁,得回到自己的项目里判断。比如做 AI 编程助手,模型回答“Bug 已修复”不算完成任务。我们要看它交出的补丁能不能解决原问题,改完以后有没有影响别的功能。
LangGraph 的 Send 适合动态扇出:图运行到某一步,才知道有几项工作要并行处理。比如解析报告得到 12 个章节,路由函数就针对 12 个章节分别返回一个 Send,指定同一个摘要节点,但给每次调用不同的章节内容和编号。
LangGraph 的 Checkpointer 保存图在某个 thread 上的状态快照,适合对话续接、暂停后恢复、查看执行历史。使用时需要稳定的 thread_id;换了 thread_id,就不是继续原任务。
Runnable 是 LangChain 里可调用、可组合的一类抽象,通常能以统一方式执行、批处理或流式处理。把若干 Runnable 按确定顺序组合起来,就形成一条固定处理链;
把 Agent 从 Demo 推到生产,我会设四类门槛。第一,目标和安全边界:什么算完成,哪些动作必须禁止或人工确认。第二,执行可靠性:工具超时、重复请求、状态恢复和幂等怎么处理。
我会把 AI 编程助手设计成一个受控闭环:先读取错误信息和仓库结构,定位相关文件;再让模型提出小范围补丁;在隔离工作区运行目标测试与必要的回归测试;最后交付补丁、测试结果和风险说明,等待人工或可信流程确认。工具不是越多越好。
多租户 AI 应用要把租户范围作为服务端确认的安全上下文,贯穿聊天会话、上传文件、解析片段、向量检索、工具调用、答案缓存和引用下载。不能相信客户端传来的 tenant_id,更不能只靠提示词告诉模型“不要泄露别家数据”。
遇到模型接口限流,我会先在入口控制并发、请求量和 Token 预算,避免把所有流量都推给供应商。可以延迟的批处理进入有上限的队列;交互请求则设置短等待预算,超出就明确降级或失败。
Prompt Cache 和答案缓存不是一回事。Prompt Cache 让模型服务复用相同前缀的计算,例如稳定的系统说明和工具定义;本次请求仍会生成新回答。答案缓存则是应用发现“这次可以复用旧结果”,直接把上次答案返回。
模型路由就是根据任务难度、风险、时延要求等,把请求交给不同模型处理。比如格式固定的意图分类可先试轻模型;跨多个条款推理、需要复杂工具规划的请求,交给更强模型。做法不是凭感觉写一堆关键词规则。
Agent 任务评测不能只看最后回答。要先为任务定义可验证的完成条件:例如代码修复要求补丁存在且指定测试通过;创建工单要求系统里有且只有一张符合要求的工单;资料调研要求结论能回溯到证据。
Agent 做计划,是为了把复杂任务拆成可验证的阶段,避免拿到一个工具结果就漫无目的地调用下一个工具。计划里应有当前假设、下一步要取的证据和完成条件。但计划不能锁死执行路径。
Agent 调工具超时,先把它看成结果未知,而不是操作失败。查询类工具通常可以设置超时、有限次数的退避重试;创建、支付、发信这类写操作不能让模型直接再调一次,因为第一次可能已经成功。
这是间接提示词注入。攻击者把指令藏在网页、邮件或检索结果里,等 Agent 读取时,试图让模型把这段外部内容当成更高优先级的命令。防护的核心是划清信任边界。外部内容只作为待处理数据进入上下文,不能获得用户或系统的授权。
我会把 RAG 的评测分成三层。第一层看检索:标准证据有没有进入候选和最终上下文;第二层看证据使用:模型说出的关键结论能不能从提供的材料里找到依据;第三层看业务答案:它是否回答了问题,条件、数值和结论是否正确。
RAG 的文档通常会被解析、切片、生成向量,再写入检索索引。修改源文件只完成了第一步,旧片段可能还留在索引、搜索副本或缓存里,所以用户仍会搜到旧答案。我会给文档和片段带上稳定 ID、版本和有效状态。
Rerank 就是对已经检索出来的一批候选,结合用户当前问题重新排序。召回阶段要尽量把可能有用的材料找进来;重排阶段再从这些材料中挑出更值得放进模型上下文的几条。
RAG 用混合检索,主要是因为关键词和向量检索擅长的题不一样。像 E_CONN_RESET 这样的错误码、订单号或条款编号,关键词匹配通常更直接;用户把原文换一种说法来问时,向量检索又更容易找到语义相近的片段。
Embedding 是把文本等内容表示成一组数字,也就是向量。两段内容在某个向量空间里距离近,通常表示它们在这个模型看来有一定相关性,因此适合拿来做语义检索。但我不会把相似度分数直接当成“答案正确率”。
Token 可以理解为模型处理文本时使用的片段单位,但它和汉字、单词都不是一一对应的。同一段内容换了语言、标点或者模型的分词方式,Token 数量就可能变。所以我不会拿“中文有多少字”直接当上下文预算。
合法 JSON 不能直接入库。它只说明语法上能解析;即使用 JSON Schema 约束了字段和类型,也只能说明结构符合预期,不能证明金额、订单归属和业务条件正确。我会把链路分几关:先检查模型调用是否完成、有没有拒答或截断;再做结构校验;
我不会默认把任务拆成多个 Agent。先用单 Agent 加明确工具,看看它是否已经能稳定完成任务。如果主要问题只是步骤多,未必需要多 Agent;真正值得拆分的,往往是专业上下文、工具权限或对话责任需要分开。
RAG 切片不是越小越好。小块通常更聚焦,检索时容易定位到某句话,但可能把主规则、前提和例外拆开;大块能保留更多上下文,却可能混入无关内容,增加重排和模型输入的负担。
Trace 是一次请求的执行轨迹,能把模型调用、检索和工具调用这些步骤串起来,帮我们定位一次失败发生在哪里。Evaluation 则是用明确的样本和标准,对一个版本或多个版本的表现做判断。两者有联系,但不是同一回事。
在 LangGraph 里,State 是任务当前的共享快照,Node 是处理一项工作的函数,Edge 决定下一步执行哪个节点。比如报表助手可以先有“用户要看哪段时间”的状态,随后两个节点分别查销售与退款,最后由汇总节点生成结论。
我会把智能客服按任务分层。政策解释类问题用 RAG 找当前适用的条款,并给出来源;涉及“我的订单”就先确认用户身份,再调用订单工具读实时数据;
企业知识库问答,我会拆成两条链路。离线链路负责文件解析、切片、元数据和索引,尤其保留来源、版本、生效时间、所属空间与权限标识;在线链路负责身份验证、权限过滤、检索、上下文组装、生成和引用。文档更新不能直接把半成品暴露给用户。
文件上传和解析建索引要分开。上传接口把文件可靠保存下来,再创建一条任务,返回文件 ID、任务 ID 和当前状态;OCR、切片、Embedding、写索引由后台 Worker 执行。
上下文窗口变大,解决的是一次能输入多少内容;它不能保证模型对长文档里每个位置、每个例外条件都同样敏感。像合同违约金,正文里可能有一条通用规则,后面又有特殊客户或特定日期的例外。模型读进去了整份合同,仍可能只拿前面的通用规则作答。
大模型的幻觉,简单说就是它给出了看似合理、却没有事实依据或者与已有证据冲突的内容。比如知识库根本没有今年的报销标准,它却报出一个具体金额。把 Temperature 调到 0,通常会让采样结果更集中、更稳定,但不会帮模型核实事实。
RAG 检索到正确文档,只能说明检索结果里出现过它,不能保证大模型拿到了完整的证据,更不能保证它按照证据答对。我会先拿一条答错的请求,对照检索结果、最终送进模型的上下文和模型输出。
MCP 和 Tool Calling 并不是二选一。Tool Calling 是模型提出工具调用的方式:应用告诉模型有哪些工具,模型返回想调用的工具和参数,真正执行仍然由应用处理。MCP 则是 AI 应用连接外部能力的一套协议。
Context 可以理解成这一轮真正交给模型看的信息。用户刚说的话、任务目标、最近的工具结果,都可能放进去;但系统保存过的内容,不代表模型这一轮一定看到了。State 记录的是任务现在进行到哪里。
如果是普通的文字聊天,用户提交一次问题,服务端持续返回回答,我会先用普通 HTTP 请求提交问题,再用 SSE 把生成内容推给页面。用户能发问题,不代表这条连接必须是双向的。
RAG 检索不到文档时,先确认答案所在的那段文字,是不是真的进入了当前可查询的索引。因为“文件上传成功”和“内容可以被检索到”是两回事。文件上传以后,通常还要经过解析、切片、生成向量和建立索引。
Tool Calling 并不是大模型自己去执行某个工具,而是模型和应用之间约定的一套调用方式。应用会先把工具名称、用途和参数结构告诉模型。模型判断需要使用工具时,会返回一份结构化的调用请求,里面通常包含工具名称、参数和调用标识。
LangGraph 通过保存执行状态,让任务能够暂停下来,等收到用户回复以后继续执行。具体来说,需要配置一个负责保存检查点的 checkpointer,并用 thread_id 标识当前线程。
Agent 的核心工作方式,可以理解成一个不断重复的执行循环,也就是 Agent Loop。任务开始以后,模型会读取用户目标和当前的任务状态,然后决定下一步做什么。
Agent 和 Workflow 的本质区别,是执行路径到底有谁来决定。Workflow 的步骤处理主要是有代码预设决定好的。那么即使中间调用了大模型,但是它本质仍然可以是 Workflow 预定好的流程。
微信搜一搜「程序员Sunday」,或扫码关注
新文章第一时间推送;站点文章需要解锁时,在公众号里回复「验证码」即可领取链接。
