6.9 KiB
MVP Agent 工程决策记录
本文记录 MVP 实现过程中已经落地的一些关键修复、取舍和工程判断。目标不是写流水账,而是沉淀面试时可以讲清楚的 Agent 工程思路。
1. 统一流式与非流式 Chat 主链路
背景
早期 /api/chat 和 /api/chat_stream 是两条不同实现:
- 非流式接口会走复杂度判断,并可能进入 Planner / Executor / Verifier 多 Agent 流程。
- 流式接口直接创建单个 ReactAgent,然后
agent.stream()输出 token。
这导致两个接口表面都是 chat,实际能力不一致:流式接口不会进入 verifier、不会沉淀完整诊断链路,也不容易和 diagnosis_session、tool_invocation 对齐。
决策
将两个接口统一到同一条核心链路:
getOrCreateSession
-> 读取会话历史
-> ChatService.executeChatWithStrategy(...)
-> 写回会话历史
接口差异只保留在传输层:
/api/chat返回完整 JSON。/api/chat_stream通过 SSE 分块发送最终答案。
取舍
这样会牺牲原来的 token 级实时流式体验,但换来业务行为一致、诊断链路一致、Verifier 和 evidence trace 一致。
对 MVP 来说,优先保证“同一个问题不因接口不同而进入不同智能链路”,比 token 级流式更重要。
2. 会话 ID 与诊断链路统一
背景
原实现中:
ChatController用前端传入的Id在 JVM 内存里维护历史消息。ChatService每次执行又生成新的 8 位 sessionId,作为diagnosis_session和工具调用追踪 ID。
这会造成前端会话、后端诊断会话、工具证据链三者分裂。
决策
将前端 chat session id 作为后端诊断链路的主 session id:
- Redis
SessionContext保存聊天历史。 diagnosis_session.session_id复用同一个 id。RunnableConfig.metadata.sessionId和SessionContextHolder也使用同一个 id。tool_invocation、agent_step、verifier evaluation 都可按同一 session id 串起来。
企业级意义
Agent 系统最怕“答得出来但查不清”。统一 session id 后,一次用户请求可以完整追踪:
用户问题 -> Agent 步骤 -> 工具调用 -> Verifier 判断 -> 最终答案 -> 用户反馈
这是可观测、可审计、可复盘的基础。
3. 引入统一 ToolInvocationRecorder
背景
Verifier 需要结构化证据链,但原实现只有 lookup_knowledge 主动写入 tool_invocation。
query_logs、query_metrics 虽然返回 JSON,但没有统一落库,导致 verifier 看不到日志、指标等 evidence tool 的稳定记录。
决策
新增 ToolInvocationRecorder,作为所有 evidence tool 的统一落库入口。
当前接入:
lookup_knowledgequery_logsquery_metrics
记录字段包括:
- tool name
- input params
- output preview
- output length
- success
- error message
- duration
- trace id / domain details
企业级意义
这一步把 Agent 从“模型说它查过”推进到“系统能证明它查过”。
后续 verifier 不应该依赖模型自由文本回忆工具调用,而应该消费结构化 trace summary。
4. Verifier 作为事实约束层
背景
普通 Agent 很容易在工具调用后直接生成答案,但企业场景更关心:
- 关键结论有没有证据
- 证据是直接证据还是间接支持
- 哪些事实缺口需要人工介入
- 工具失败时是否诚实降级
决策
保留 Planner / Executor / Verifier 三角色:
- Planner 负责拆解问题。
- Executor 负责执行查询与形成初稿。
- Verifier 负责基于
tool_trace_summary做事实核查。
Verifier 输出结构化 JSON,包括:
- verdict
- groundedness_score
- critical_fact_count
- facts_checked
- rationale
取舍
Verifier 会增加一次模型调用成本,但换来可解释性和质量约束。对企业级 Agent 来说,这是值得的。
5. 从手写编排切换到 SupervisorAgent
背景
之前 ChatService.executeChatComplex() 中构建了 SupervisorAgent,但实际仍然手写调用:
planner -> executor -> verifier
这会造成代码与设计不一致,维护者容易误以为当前已经由 Supervisor 调度。
决策
复杂问题真正切换到 SupervisorAgent.invoke(...)。
Supervisor 负责路由:
chat_supervisor -> chat_planner
chat_supervisor -> chat_executor
chat_supervisor -> chat_verifier
chat_supervisor -> FINISH
外层仍保留:
- verifier 输出解析
- PASS / LOW_CONFID / REJECT 判定
- retry context
- fallback
- evaluation 入库
验证
新增离线专项测试 ChatServiceSupervisorAgentTest,使用 scripted ChatModel 验证真实 SupervisorAgent 路由顺序,不依赖真实 LLM、MySQL、Redis。
企业级意义
这让项目不只是“自己写 if/else 多 Agent”,而是使用框架原生 multi-agent orchestration,同时保留业务层的质量门控。
6. 文档上传路径语义统一
背景
上传文档时,DocumentManagementService.saveToLocal() 返回带 knowledge_base 前缀的路径。
而 KnowledgeIndexService.readDocument() 又执行:
Paths.get(knowledgeBasePath, filePath)
这可能拼出:
knowledge_base/knowledge_base/...
最终表现为 L0 命中文档,但读取原文失败。
决策
统一路径语义:
- 新上传文档存相对
knowledge.base-path的路径,例如payment/runbook.md。 readDocument()兼容新旧路径:- 相对路径
- 已带 base path 的旧相对路径
- 绝对路径
企业级意义
知识库检索不能只看“命中”,还要保证命中后的内容可读、可引用、可追踪。
这是 RAG / Agent 系统里很典型的工程细节:检索质量问题不一定来自模型,也可能来自路径、元数据、索引和原文之间的语义不一致。
7. MVP 阶段的优先级取舍
当前主动暂缓的问题:
- 敏感配置外置与密钥轮换
- CORS / Redis 反序列化安全边界
- 默认
mvn test离线化
原因不是这些不重要,而是当前目标是先跑通并讲清楚 MVP Agent 工程闭环。
短期优先目标:
可演示 -> 可观测 -> 可验证 -> 可复盘
安全和完整测试体系属于企业落地必须项,但可以在 MVP 主链路稳定后作为下一阶段补齐。
8. 后续建议
下一阶段建议聚焦“可复现 MVP Demo”:
- 增加
local-demo或mvp-demoprofile。 - 准备固定诊断 case,例如“支付接口超时”。
- 提供一键初始化知识库样例。
- 提供一键触发复杂诊断请求的脚本。
- 增加 trace 查询接口:
GET /api/diagnosis/{sessionId}/trace
该接口聚合:
- diagnosis_session
- agent_step
- tool_invocation
- verifier evaluation
- final answer
- feedback
这样 MVP 就能从“功能实现”升级为“企业级 Agent 工程作品”。