04 - 任务 Agent 编排与状态机实践篇

核心定位:严肃政务场景下的 Task Agent 落地,深入 Plan-Act 架构、工具白名单沙箱、有限状态机(FSM)、步数熔断与长任务状态同步。


Q1: 你们系统中的 Chat 模式和任务 Agent 模式有什么区别?用户请求到来时,是如何进行意图识别与模式路由的?

回答(求职者口吻)
我们在业务层将大模型应用明确划分为两种运行形态:

  1. Chat 模式(轻量即时问答)
    - 特点:单次检索、单次推理、低延迟(首字响应 < 1.5s)、纯只读 RAG。面向用户的日常政策条文查阅、办事材料咨询等明确问题。
  2. 任务 Agent 模式(复杂多步目标驱动)
    - 特点:用户下达高层次复合目标(如“汇总近三年制造业税收优惠并对比省市差异”、“对标深圳优化营商环境十条措施”)。需要系统自动拆解子任务、多次调用不同工具(多轮知识检索、数据提取、表格对比、格式化渲染)、流转状态机并耗时数秒至数十秒。

意图识别与模式路由机制
- 前端显式切换与隐式智能路由结合
- 用户可在小程序/Web 界面显式选择“政策快答”或“深度研究助手”;
- 若在默认对话框输入,后端入口通过轻量级 Fast-LLM(结合 Few-Shot 分类与关键词意图分类器)进行意图分流。如果判定包含“对比、汇总、演变分析、对标、生成简报”等强动作指令且涉及跨域或多步操作,自动路由至 Agent 任务编排引擎,并在前端界面无缝切换为步骤进度流展示。


Q2: 任务 Agent 的整体架构是怎么设计的?为什么选择基于「计划-执行(Plan-and-Solve)」而不是直接用自由 ReAct 循环或复杂的开源通用框架?

回答(求职者口吻)
这是我们在政务业务严肃性要求下的关键架构选型:

  • 为什么不选纯自由 ReAct(Reasoning + Acting)循环
  • ReAct 模式高度依赖模型在每一步的单步反思与工具选择。在实际测试中,开源大模型在面对复杂的政务多步长链路时,极易出现“死循环调用同一工具”、“偏离初始目标(Goal Drifting)”或“随机停机”。对于企业级政务应用,不可控的黑盒循环是无法被业务接受的。
  • 我们的 Plan-and-Solve 状态机架构
    1. Planner(规划阶段):接收用户目标,调用模型生成严格的 JSON 格式执行计划列表(Execution Plan DAG),例如 [Step1: 检索A, Step2: 检索B, Step3: 矩阵对比, Step4: 组装简报]
    2. Validator(计划校验与安全审查):业务层对生成的 Plan 进行确定性校验:检查涉及的工具是否在白名单内、总步数是否超限(默认 $\le 5$ 步)、参数模式是否合法。
    3. Executor(执行阶段):后端调度器按顺序触发工具调用,前一步的输出结构化暂存并作为后一步的输入上下文。
    4. Synthesizer(合成输出):所有步骤完成后,汇总上下文生成最终符合政务公文格式的 Markdown/表格简报。

这种架构将“创造性的规划”与“确定性的执行”完全解耦,既保留了大模型理解复杂任务的灵活性,又把执行控制权牢牢掌握在后端的确定性代码逻辑中。


Q3: 详细讲讲工具调用(Tool Calling / Function Calling)的完整链路与工具白名单机制。

回答(求职者口吻)
我们设计了闭环的 Tool Calling 架构,重点实现强类型参数校验与严格的权限沙箱

  1. 工具元数据标准声明(JSON Schema)
    - 每个可用工具必须在 Go 后端通过标准 Schema 显式注册,定义工具名称、功能描述、入参类型、必填字段及正则约束。
    - 示例工具集:rag_search_tool(多域知识检索)、policy_diff_tool(条款差异比对)、entity_extract_tool(公文实体提取)、report_export_tool(生成导出文件)。
  2. 工具白名单与基于角色的权限过滤(Tool Whitelist & RBAC)
    - 不同的用户角色拥有不同的工具权限。在将 Tool 定义下发给大模型时,业务层根据当前用户 Token 动态过滤工具列表。例如:普通基层人员只下发只读检索类工具;具备研究审批权限的领导账号才下发跨库全量对比和批量导出工具。大模型永远看不到未授权工具的元数据。
  3. 参数强校验拦截器(Parameter Interceptor)
    - 大模型输出 Function Call JSON 后,Go 业务层拦截器通过反射与 JSON Schema 校验器对参数进行严格类型断言,清洗注入字符(防止 SQL 注入、Prompt 注入与目录遍历),校验通过后才路由至具体的本地/RPC 工具函数执行。

Q4: 严肃政务场景下,如何防止 Agent 陷入死循环、滥用工具或耗尽资源?你们设置了哪些硬性安全护栏(Guardrails)?

回答(求职者口吻)
为了防止 Agent 失控,我们在业务层构建了五大硬性熔断与防护栏(Hard Guardrails):

  1. 最大步数熔断(Max Steps Limit)
    - 单个 Agent 任务的规划与执行步数严格限制在 5 步以内。若达到第 5 步任务仍未主动结束,状态机强制终止执行,利用当前已收集的中间产物进入兜底合成流程。
  2. 最大检索次数与 Token 预算(Token & Search Budget)
    - 单任务限制调用 RAG 检索最多 4 次,单任务累计消耗上下文 Token 上限设定为 16k。一旦累计 Token 触达水位线,阻断后续工具调用,立即进入结果总结。
  3. 全局超时控制(Global Execution Timeout)
    - 整体长任务通过 context.WithTimeout 设置硬超时阈值(如 60s),单步工具调用超时设为 10s,超时后立即释放协程与网络连接。
  4. 工具调用幂等与重复检测
    - 维护工具调用哈希指纹 Hash(tool_name + sorted_params)。若检测到连续两次调用相同工具且参数完全一致,判定为推理陷入局部震荡,强制跳出循环。
  5. 危险操作只读约束
    - Agent 模式在政务系统中严格限定为“只读与分析型”,禁止任何涉及数据库写入、配置变更或外网通信的动作。

Q5: 任务 Agent 的底层状态机(State Machine)是如何设计的?包含哪些核心状态?中间状态如何持久化?

回答(求职者口吻)
我们基于有限状态机(FSM)模型设计了任务全生命周期的状态跃迁,核心包含以下 7 种状态:

  • CREATED(任务创建与入队)
  • PLANNING(大模型正在进行目标分解与步骤规划)
  • RUNNING(正在按步骤调度执行工具)
  • WAITING_USER(特殊场景下等待用户补充输入或确认)
  • SYNTHESIZING(各步骤完成,正在生成最终综合简报)
  • SUCCESS(任务成功交付)
  • FAILED / CANCELLED(任务失败熔断或用户主动取消)

状态跃迁与持久化机制
- Redis 实时状态与缓存:当前执行步骤、实时进度百分比、各步骤临时输出缓存在 Redis Hash 中,提供毫秒级的 SSE 实时读取通道。
- MySQL 最终持久化:每次状态发生流转(如从 PLANNING -> RUNNING,或 Step 1 完成),通过事务或异步管道更新 MySQL agent_task 表与 agent_task_step 表,记录每个步骤的耗时、入参、出参及 Token 消耗。
- 故障恢复:若执行节点意外重启,调度器扫描处于 RUNNING 且心跳超时的任务,可依据已持久化的 Step 记录决定断点续跑或置为异常失败。


Q6: 复杂对比任务耗时较长(可能需要 15~30 秒),如何向小程序前端实时同步任务进度和分步执行结果?

回答(求职者口吻)
为了彻底消除用户面对长时间白屏或加载动画的焦虑感,我们采用了“SSE 结构化事件流(Event-Driven SSE Stream)”推送机制:

  1. 分级事件定义(Event Types)
    - 我们定义了标准的 SSE 协议事件格式:
    • event: plan_created(下发整体计划列表:共 N 步,每步的目标描述);
    • event: step_start(通知前端第 X 步开始执行,附带步骤标题);
    • event: step_chunk(若该步骤涉及流式检索或流式解析,实时推送中间文字);
    • event: step_finish(通知第 X 步执行完毕,返回该步骤结构化卡片);
    • event: final_result(全量简报合成完成,附带引用来源列表与下载链接);
    • event: task_error(异常中断提示)。
  2. 端侧动态渲染体验
    - 微信小程序端接收到 SSE 事件后,动态渲染时间轴进度条(Timeline UI)。用户可以直观看到“对勾已完成步骤”、“当前正在旋转的进行中步骤”以及“实时打印的分析日志”,极大提升了交互过程中的专业感和信任感。

Q7: 如果 Agent 在执行到第 3 步时某个工具调用失败(例如底层网络抖动或知识库无命中),状态机如何处理?

回答(求职者口吻)
我们遵循“局部重试 -> 降级容错 -> 优雅降级合成”的三层容错策略,而不是直接给用户抛出冷冰冰的 500 错误:

  1. 瞬时异常局部重试
    - 若失败原因为网络瞬时超时(HTTP 504 / Connection Reset),工具执行器自动进行 1 次指数退避重试(Backoff Retry)。
  2. 业务无数据容错标注
    - 若重试后依然失败,或工具返回“未检索到相关数据”,状态机不会直接崩溃,而是将该步骤的输出标记为结构化的异常提示:“【步骤3异常】:未在指定库中检索到相关法规条款”。
  3. 部分上下文兜底合成(Graceful Partial Degradation)
    - 调度器跳过失败步骤或带着异常标注继续推进至 SYNTHESIZING 阶段,指导大模型在生成总简报时明确说明:“受限于知识库数据,关于 X 维度的对比数据暂缺,以下基于已成功检索的 Y 维度为您展示分析结果…”,最大化交付有效信息。

Q8: Agent 模式下的 Token 消耗和调用延迟远高于普通问答,你们在工程上做了哪些优化?

回答(求职者口吻)
我们在工程链路上实施了全方位的“减负与降本增效”优化:

  1. 小模型规划,大模型合成(Model Routing)
    - 在 Planning 阶段和 Tool Parameter 提取阶段,使用参数量小、响应极快、成本低的轻量模型(如 7B/14B 模型或 fast-API),延迟仅需数百毫秒;而在最后的综合简报写作(Synthesizing)阶段,才调用能力最强的旗舰大模型,大幅降低总体耗时与 Token 成本。
  2. 中间上下文字符剪枝与摘要(Context Pruning)
    - 工具调用返回的原始 RAG Chunk 可能包含大量格式干扰字符。业务层在将中间结果回填给下一步 Prompt 之前,进行严格的正则清洗和精简,只保留核心语义片段,避免长上下文无意义膨胀。
  3. 高频计划模板缓存(Plan Caching)
    - 针对常见的政策对比模式(如“对比 A 地与 B 地在 C 领域的政策”),将经典的 Plan 结构缓存至 Redis,匹配相似意图时直接复用标准执行计划,跳过第一步 LLM 规划耗时。

Q9: 为什么在政务场景中不采用全开放的自主 Agent(如 AutoGPT 自行决定调用任意 API 或执行 Shell 脚本)?

回答(求职者口吻)
在政务、金融等高合规性领域,“确定性、安全性、可解释性”永远高于“完全开放的自主性”

  1. 安全红线与注入防御:全开放 Agent 极易受到 Prompt 注入攻击(Prompt Injection)。恶意用户可能在公文内容中构造恶意指令诱导 Agent 执行未授权操作。严格限制在只读工具白名单内,从根本上杜绝了远程命令执行(RCE)或数据泄露的可能。
  2. 政务流程标准化要求:政务公文与政策研究有固定的行政规范和逻辑标准(如发文字号、效力层级、对比维度),不需要模型进行不可控的发散创作,而是需要系统严格按既定政策研究框架严谨执行。
  3. 可审计性与责任归属:白名单 + 状态机模式下,每一步调用的工具、参数、数据源均有精确的落库日志,遇到答复异议时可以 100% 重现并复盘执行路径。

Q10: 任务完成后,最终结构化成果(如 Word 简报、表格矩阵、审计报告)是如何组装、存储并交付给用户的?

回答(求职者口吻)
我们构建了完整的结构化交付管道:

  1. Markdown 渲染与多媒体混排
    - 大模型在合成阶段直接输出标准 GitHub Flavored Markdown,包含政策对比表格、加粗核心条款及引用编号。
  2. 异步后端文档生成引擎
    - 当用户在 Web 管理端点击“导出政务简报”时,后端 Go 服务调用基于模板引擎的文档转换模块,将结构化 Markdown、元数据表头(生成时间、发文机构、研究员署名)渲染为符合公文排版标准的 DOCX 或 PDF 文件。
  3. 对象存储安全托管与临时鉴权
    - 生成的文档上传至 MinIO/私有云对象存储,业务层生成带有短期有效签名的安全临时下载链接(Pre-signed URL,有效期 10 分钟),保障文件传输安全且不占用应用服务器磁盘。