421 lines
20 KiB
Markdown
421 lines
20 KiB
Markdown
|
|
# 小财管家 LangGraph Runtime 迁移计划
|
|||
|
|
|
|||
|
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
|||
|
|
|
|||
|
|
**Goal:** 把小财管家的感知、规划、记忆、确认和行动逐步迁到 LangGraph runtime,减少自研流程编排里的隐藏状态和分支 bug。
|
|||
|
|
|
|||
|
|
**Architecture:** 保留现有 FastAPI API、Pydantic schema、`RuntimeChatService` 模型供应商抽象和业务服务;LangGraph 只接管 agent 编排。副作用动作必须通过白名单 action node 调用现有业务服务,保存草稿、提交和关联单据都不能由模型文本直接触发。
|
|||
|
|
|
|||
|
|
**Tech Stack:** Python 3.11、FastAPI、Pydantic、LangGraph 1.x、SQLAlchemy、现有 `AgentConversationService` / `StewardFlowStateService`。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 当前状态
|
|||
|
|
|
|||
|
|
已经完成第一阶段接入:
|
|||
|
|
|
|||
|
|
- `server/src/app/services/steward_graph_planner.py`
|
|||
|
|
- 已新增 `StewardGraphPlannerService`。
|
|||
|
|
- 已用 LangGraph `StateGraph` 编排 `prepare_context -> detect_model_intent -> done/off_topic/rule_fallback`。
|
|||
|
|
- `server/src/app/services/steward_graph_runtime.py`
|
|||
|
|
- 已新增 `StewardGraphRuntime`。
|
|||
|
|
- 槽位决策已编排为 `slot_prepare_context -> slot_tool_decision -> done/rule_fallback`。
|
|||
|
|
- 运行时决策已编排为 `runtime_memory_context -> runtime_action_decision/runtime_tool_decision -> done/rule_fallback`。
|
|||
|
|
- 图内失败会降级到原有规则兜底;端点层图运行异常会回退旧 Agent。
|
|||
|
|
- `server/src/app/services/steward_action_contracts.py`
|
|||
|
|
- 已新增 `StewardActionPlanBuilder`。
|
|||
|
|
- 已把申请、报销、保存草稿、直接提交规划成 `StewardActionStep` 白名单动作。
|
|||
|
|
- `StewardGraphPlannerService` 已增加 `attach_action_steps` 节点,计划返回前统一补全动作列表。
|
|||
|
|
- `server/src/app/services/steward_action_executor.py`
|
|||
|
|
- 已新增 `StewardActionExecutor`。
|
|||
|
|
- 已接入 `/steward/actions/execute`,支持未知动作拒绝、缺字段阻断、提交确认门禁、重复申请 precheck、申请/报销草稿真实执行、关联申请单和附件关联。
|
|||
|
|
- 申请动作复用 `UserAgentService` 的申请保存/提交能力,报销草稿复用 `ExpenseClaimService.save_or_submit_from_ontology()`。
|
|||
|
|
- `server/src/app/services/steward_graph_action_runtime.py`
|
|||
|
|
- 已新增 `StewardGraphActionRuntime`。
|
|||
|
|
- 已用 LangGraph `StateGraph` 编排 `action_checkpoint_load -> action_execute_node -> action_checkpoint_persist`。
|
|||
|
|
- 已通过 `conversation_id + client_trace_id` 在 `AgentConversation.state_json` 中记录 checkpoint、pending interrupt 和幂等重放结果。
|
|||
|
|
- `web/src/services/steward.js` / `web/src/views/scripts/stewardPlanModel.js`
|
|||
|
|
- 前端已新增 `executeStewardAction()` 服务方法。
|
|||
|
|
- steward suggested action 已携带服务端可执行 action step,旧申请预览流仍保留兜底。
|
|||
|
|
- `web/src/composables/workbenchAiMode/useWorkbenchAiActionRouter.js`
|
|||
|
|
- AI 工作台点击 `steward_execute_action` 时会调用 `/steward/actions/execute`。
|
|||
|
|
- 直接提交会先执行 `run_duplicate_precheck`,precheck 通过后再提交申请。
|
|||
|
|
- `server/src/app/api/v1/endpoints/steward.py`
|
|||
|
|
- `/steward/plans` 和 `/steward/plans/stream` 默认使用 `StewardGraphPlannerService`。
|
|||
|
|
- `/steward/slot-decisions` 和 `/steward/runtime-decisions` 默认使用 `StewardGraphRuntime`。
|
|||
|
|
- `STEWARD_AGENT_RUNTIME=legacy` 可回退旧 `StewardPlannerService`。
|
|||
|
|
- `server/pyproject.toml` / `server/uv.lock`
|
|||
|
|
- 已加入 `langgraph>=1.2.0,<2.0.0`。
|
|||
|
|
- `server/tests/test_steward_graph_planner.py`
|
|||
|
|
- 已覆盖默认 LangGraph、显式 LangGraph、legacy 回退、模型成功计划和模型失败后规则兜底。
|
|||
|
|
- `server/tests/test_steward_graph_runtime.py`
|
|||
|
|
- 已覆盖槽位工具节点、图内规则兜底、运行时记忆合并、确定性行动选择和端点级 legacy 兜底。
|
|||
|
|
- `server/tests/test_application_fact_resolver.py`
|
|||
|
|
- 已覆盖 `交通火车` 不污染申请事由,以及 `高铁往返` 这类业务描述仍保留。
|
|||
|
|
|
|||
|
|
当前已完成规划入口、slot decision、runtime decision、基础 action contract、第一版 action executor、前端点击执行闭环,以及 action runtime 的 checkpoint / interrupt / 幂等重放。
|
|||
|
|
真实外部模型连通性仍需要用当前 MiniMax / backup 配置再回放确认。
|
|||
|
|
|
|||
|
|
## 官方能力边界
|
|||
|
|
|
|||
|
|
LangGraph 官方文档强调它是低层 agent orchestration runtime,重点能力是 durable execution、streaming、human-in-the-loop 和 persistence。
|
|||
|
|
|
|||
|
|
本项目只采用这些底层编排能力:
|
|||
|
|
|
|||
|
|
- Graph API:用 state、node、edge 表达流程,node 可以是 LLM 调用,也可以是普通业务代码。
|
|||
|
|
- Persistence:用 checkpointer 保存 thread scoped state,用 store 保存跨线程长期信息。
|
|||
|
|
- Interrupt:在需要用户确认时暂停 graph,等待外部输入后恢复。
|
|||
|
|
|
|||
|
|
参考:
|
|||
|
|
|
|||
|
|
- <https://docs.langchain.com/oss/python/langgraph/overview>
|
|||
|
|
- <https://docs.langchain.com/oss/python/langgraph/graph-api>
|
|||
|
|
- <https://docs.langchain.com/oss/python/langgraph/persistence>
|
|||
|
|
- <https://docs.langchain.com/oss/python/langgraph/interrupts>
|
|||
|
|
|
|||
|
|
## 总体目标架构
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
用户输入 / 前端上下文 / 附件
|
|||
|
|
↓
|
|||
|
|
StewardGraphRuntime
|
|||
|
|
├── prepare_context_node
|
|||
|
|
├── model_intent_node
|
|||
|
|
├── slot_decision_node
|
|||
|
|
├── flow_guard_node
|
|||
|
|
├── action_plan_node
|
|||
|
|
├── human_review_node
|
|||
|
|
├── action_execute_node
|
|||
|
|
├── persist_state_node
|
|||
|
|
└── response_adapter_node
|
|||
|
|
↓
|
|||
|
|
现有前端协议:StewardPlanResponse / StewardRuntimeDecisionResponse / StewardSlotDecisionResponse
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
关键原则:
|
|||
|
|
|
|||
|
|
- API 响应协议稳定,前端不因为 runtime 替换被迫大改。
|
|||
|
|
- 模型只负责理解、拆步骤、给候选 action,不直接写库。
|
|||
|
|
- 所有副作用节点必须调用现有业务服务,并保留确认和审计。
|
|||
|
|
- `RuntimeChatService` 继续是唯一模型调用入口,LangGraph 不直接管理供应商密钥。
|
|||
|
|
- `StewardFlowStateService` 和 `AgentConversationService` 是 checkpoint 落库的第一候选,不另起一套状态源。
|
|||
|
|
|
|||
|
|
## Runtime State 草案
|
|||
|
|
|
|||
|
|
第一版 graph state 用 `TypedDict`,后续需要持久化时再评估 Pydantic schema。
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
class StewardGraphState(TypedDict, total=False):
|
|||
|
|
request: StewardPlanRequest
|
|||
|
|
conversation_id: str
|
|||
|
|
thread_id: str
|
|||
|
|
message: str
|
|||
|
|
base_date: date
|
|||
|
|
steward_state: dict[str, Any]
|
|||
|
|
model_call_traces: list[dict[str, Any]]
|
|||
|
|
intent_result: StewardIntentAgentResult | None
|
|||
|
|
slot_decision: StewardSlotDecisionResponse | None
|
|||
|
|
runtime_decision: StewardRuntimeDecisionResponse | None
|
|||
|
|
action_plan: list[StewardActionStep]
|
|||
|
|
pending_interrupt: dict[str, Any]
|
|||
|
|
action_result: dict[str, Any]
|
|||
|
|
response: StewardPlanResponse | StewardRuntimeDecisionResponse | StewardSlotDecisionResponse
|
|||
|
|
fallback_reason: str
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
`thread_id` 推荐使用现有 `conversation_id`,这样 LangGraph checkpoint、业务会话和前端会话能对齐。
|
|||
|
|
|
|||
|
|
## 节点边界
|
|||
|
|
|
|||
|
|
### 感知节点
|
|||
|
|
|
|||
|
|
- `prepare_context_node`
|
|||
|
|
- 输入:`StewardPlanRequest` 或 runtime decision request。
|
|||
|
|
- 输出:清洗后的消息、base date、当前 conversation state。
|
|||
|
|
- 禁止:模型调用、数据库写入。
|
|||
|
|
|
|||
|
|
- `model_intent_node`
|
|||
|
|
- 调用:`StewardIntentAgent.detect()`。
|
|||
|
|
- 约束:保留 `timeout_seconds=10`、`max_attempts=3`、`use_failure_cooldown=False`。
|
|||
|
|
- 失败:只写入 `fallback_reason` 和 `model_call_traces`,不吞掉错误上下文。
|
|||
|
|
|
|||
|
|
### 决策节点
|
|||
|
|
|
|||
|
|
- `slot_decision_node`
|
|||
|
|
- 迁移对象:`StewardSlotDecisionAgent.decide()`。
|
|||
|
|
- 目标:让字段缺口判断进入同一个 graph state,不再由前端和后端多个入口各自推断。
|
|||
|
|
|
|||
|
|
- `runtime_decision_node`
|
|||
|
|
- 迁移对象:`StewardRuntimeDecisionAgent.decide()`。
|
|||
|
|
- 目标:用户补字段、确认流程、取消当前动作、继续下一任务都走 graph routing。
|
|||
|
|
|
|||
|
|
- `flow_guard_node`
|
|||
|
|
- 负责申请/报销歧义、重复单据、时间重叠、低置信度、off-topic。
|
|||
|
|
- 低置信度或强冲突必须进入确认或阻断,不允许继续 action 执行。
|
|||
|
|
|
|||
|
|
### 行动节点
|
|||
|
|
|
|||
|
|
- `action_plan_node`
|
|||
|
|
- 输出白名单步骤,例如 `build_application_preview`、`save_application_draft`、`submit_application`。
|
|||
|
|
- 禁止输出自由文本 action。
|
|||
|
|
|
|||
|
|
- `human_review_node`
|
|||
|
|
- 对保存草稿、提交审批、关联申请单等副作用动作生成 interrupt payload。
|
|||
|
|
- 第一阶段可继续返回前端确认动作;第二阶段再接 LangGraph `interrupt()`。
|
|||
|
|
|
|||
|
|
- `action_execute_node`
|
|||
|
|
- 只能调用现有业务服务。
|
|||
|
|
- 必须幂等,或在执行前检查动作是否已完成。
|
|||
|
|
- 提交类动作必须检查 `confirmation_required` 和用户确认来源。
|
|||
|
|
|
|||
|
|
- `persist_state_node`
|
|||
|
|
- 合并 `StewardFlowStateService.merge_plan()` / `merge_state()`。
|
|||
|
|
- 后续接入 LangGraph checkpointer 后,这里负责业务状态与 checkpoint 的一致性。
|
|||
|
|
|
|||
|
|
### 响应节点
|
|||
|
|
|
|||
|
|
- `response_adapter_node`
|
|||
|
|
- 输出现有 Pydantic response。
|
|||
|
|
- 必须保留 `model_call_traces`、`planning_source`、`steward_state`。
|
|||
|
|
|
|||
|
|
## 分阶段计划
|
|||
|
|
|
|||
|
|
### Phase 0:规划入口接入 LangGraph
|
|||
|
|
|
|||
|
|
状态:已完成。
|
|||
|
|
|
|||
|
|
完成标准:
|
|||
|
|
|
|||
|
|
- [x] 默认 runtime 为 `langgraph`。
|
|||
|
|
- [x] `STEWARD_AGENT_RUNTIME=legacy` 可回退。
|
|||
|
|
- [x] `/steward/plans` 真实接口仍返回兼容的 `StewardPlanResponse`。
|
|||
|
|
- [x] 模型失败后仍按 10s * 3 次再规则降级。
|
|||
|
|
|
|||
|
|
### Phase 1:修通模型成功路径
|
|||
|
|
|
|||
|
|
目标:让真实保存草稿话术至少能走一次 `llm_function_call` 成功路径。
|
|||
|
|
|
|||
|
|
文件:
|
|||
|
|
|
|||
|
|
- 修改:`server/src/app/services/runtime_chat.py`
|
|||
|
|
- 修改:`server/src/app/services/settings.py`
|
|||
|
|
- 修改:`server/tests/test_runtime_chat_service.py`
|
|||
|
|
- 测试:`server/tests/test_steward_intent_agent.py`
|
|||
|
|
|
|||
|
|
步骤:
|
|||
|
|
|
|||
|
|
- [x] 写失败测试:模拟 main provider 超时但 backup provider 可用时,`complete_with_tool_call()` 返回 backup 的 tool call。
|
|||
|
|
- [x] 确认 backup function calling 会在 main 失败后返回 tool call,不等待 main 重试结束。
|
|||
|
|
- [ ] 写失败测试:MiniMax 返回非 OpenAI tool call 兼容格式时,服务端能记录清晰 trace 并降级。
|
|||
|
|
- [x] 容器内运行:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
docker exec -w /app -e SERVER_VENV_DIR=/tmp/x-financial-server-venv x-financial-local-linux \
|
|||
|
|
timeout 60s /tmp/x-financial-server-venv/bin/pytest -q \
|
|||
|
|
server/tests/test_runtime_chat_service.py \
|
|||
|
|
server/tests/test_steward_intent_agent.py
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
验收:
|
|||
|
|
|
|||
|
|
- [ ] 真实 `/api/v1/steward/plans` 对保存草稿原句返回 `planning_source=llm_function_call`。
|
|||
|
|
- [x] `model_call_traces` 能区分 main 失败、backup 成功或全失败。
|
|||
|
|
|
|||
|
|
### Phase 2:slot/runtime decision 迁入 graph
|
|||
|
|
|
|||
|
|
目标:把字段缺口和运行时动作判断从独立 agent 类迁进同一个 graph runtime。
|
|||
|
|
|
|||
|
|
状态:已完成。
|
|||
|
|
|
|||
|
|
文件:
|
|||
|
|
|
|||
|
|
- 已创建:`server/src/app/services/steward_graph_runtime.py`
|
|||
|
|
- 已修改:`server/src/app/api/v1/endpoints/steward.py`
|
|||
|
|
- 已测试:`server/tests/test_steward_graph_runtime.py`
|
|||
|
|
- 保留测试:`server/tests/test_steward_slot_decision_agent.py`
|
|||
|
|
- 保留测试:`server/tests/test_steward_runtime_decision_agent.py`
|
|||
|
|
|
|||
|
|
步骤:
|
|||
|
|
|
|||
|
|
- [x] 写失败测试:`StewardGraphRuntime.decide_slot()` 调用 slot node 后返回与现有 `StewardSlotDecisionAgent.decide()` 等价的 response。
|
|||
|
|
- [x] 写失败测试:`StewardGraphRuntime.decide_runtime()` 在用户补充字段时合并 `steward_state`。
|
|||
|
|
- [x] 把 `StewardSlotDecisionAgent` 包成 `slot_tool_decision` 节点。
|
|||
|
|
- [x] 把 `StewardRuntimeDecisionAgent` 包成 `runtime_tool_decision` 节点。
|
|||
|
|
- [x] 把已选流程确认和当前运行时记忆归一化拆成 `runtime_memory_context` / `runtime_action_decision` 节点。
|
|||
|
|
- [x] endpoint 在 `STEWARD_AGENT_RUNTIME=langgraph` 时使用 graph runtime。
|
|||
|
|
- [x] endpoint 在 graph runtime 异常时回退旧 Agent,避免框架层失效影响会话。
|
|||
|
|
|
|||
|
|
验收:
|
|||
|
|
|
|||
|
|
- [x] `slot-decisions`、`runtime-decisions` 和 `plans` 三个入口都由 LangGraph runtime 路由。
|
|||
|
|
- [x] legacy 回退仍可用。
|
|||
|
|
- [x] 图内工具节点失败时仍有可执行规则兜底。
|
|||
|
|
|
|||
|
|
### Phase 3:action node 标准化
|
|||
|
|
|
|||
|
|
目标:把保存草稿、提交审批、关联申请单这些副作用动作变成显式 action node。
|
|||
|
|
|
|||
|
|
状态:基础 action contract、第一版 action executor、前端点击执行闭环、LangGraph action node、checkpoint、pending interrupt 和幂等重放已完成;后续只剩 durable checkpointer 抽象与更完整 trace UI。
|
|||
|
|
|
|||
|
|
文件:
|
|||
|
|
|
|||
|
|
- 已创建:`server/src/app/services/steward_action_executor.py`
|
|||
|
|
- 已创建:`server/src/app/services/steward_action_contracts.py`
|
|||
|
|
- 已创建:`server/src/app/services/steward_graph_action_runtime.py`
|
|||
|
|
- 已修改:`server/src/app/api/v1/endpoints/steward.py`
|
|||
|
|
- 已修改:`server/src/app/services/steward_graph_planner.py`
|
|||
|
|
- 已修改:`server/src/app/schemas/steward.py`
|
|||
|
|
- 已修改:`web/src/services/steward.js`
|
|||
|
|
- 已修改:`web/src/views/scripts/stewardPlanModel.js`
|
|||
|
|
- 已修改:`web/src/composables/workbenchAiMode/useWorkbenchAiActionRouter.js`
|
|||
|
|
- 已修改:`web/src/composables/workbenchAiMode/usePersonalWorkbenchAiMode.js`
|
|||
|
|
- 已测试:`server/tests/test_steward_action_executor.py`
|
|||
|
|
- 已测试:`server/tests/test_steward_graph_planner.py`
|
|||
|
|
- 已测试:`server/tests/test_steward_planner.py`
|
|||
|
|
- 已测试:`web/tests/workbench-ai-intent-planner-model.test.mjs`
|
|||
|
|
- 已测试:`web/tests/steward-actions-service.test.mjs`
|
|||
|
|
- 已测试:`web/tests/steward-plan-message-copy.test.mjs`
|
|||
|
|
- 已测试:`web/tests/workbench-ai-action-router.test.mjs`
|
|||
|
|
|
|||
|
|
白名单 action:
|
|||
|
|
|
|||
|
|
- `build_application_preview`
|
|||
|
|
- `save_application_draft`
|
|||
|
|
- `submit_application`
|
|||
|
|
- `link_existing_application`
|
|||
|
|
- `create_reimbursement_draft`
|
|||
|
|
- `associate_attachments`
|
|||
|
|
|
|||
|
|
步骤:
|
|||
|
|
|
|||
|
|
- [x] 写失败测试:申请直接提交计划必须输出 `fill_application_fields -> build_application_preview -> validate_required_fields -> run_duplicate_precheck -> submit_application`。
|
|||
|
|
- [x] 写失败测试:保存草稿计划必须输出 `save_application_draft`,并在字段缺失时阻断后续副作用。
|
|||
|
|
- [x] 写失败测试:报销计划必须输出 `fill_reimbursement_fields -> build_reimbursement_preview -> validate_required_fields -> create_reimbursement_draft`。
|
|||
|
|
- [x] 在 `StewardTask` 和 `StewardPlanResponse` 中增加 `action_steps`。
|
|||
|
|
- [x] 实现 `StewardActionPlanBuilder`,由服务端确定性生成白名单 action step。
|
|||
|
|
- [x] 在 LangGraph planner 中新增 `attach_action_steps` 节点。
|
|||
|
|
- [x] 前端 planner model 优先消费服务端 `task.action_steps`,旧响应才回退本地推导。
|
|||
|
|
- [x] 写失败测试:未知 action step 被拒绝,不调用任何业务服务。
|
|||
|
|
- [x] 写失败测试:`submit_application` 缺少确认来源时返回 `needs_confirmation`。
|
|||
|
|
- [x] 写失败测试:`submit_application` 必须看到 precheck 通过后才允许真实提交。
|
|||
|
|
- [x] 实现 action registry,只允许白名单 action。
|
|||
|
|
- [x] 接入现有申请保存草稿、申请提交和报销草稿服务。
|
|||
|
|
- [x] 前端新增 `executeStewardAction()` 并让 suggested action 携带服务端 action step。
|
|||
|
|
- [x] AI 工作台点击 suggested action 时调用 `StewardActionExecutor`;直接提交先串行执行 precheck,再把结果交给 submit。
|
|||
|
|
- [x] 接入 `link_existing_application` 和附件关联的真实执行。
|
|||
|
|
- [x] 把 action executor 包成 LangGraph `action_execute_node`,并接入 checkpoint / interrupt 恢复。
|
|||
|
|
|
|||
|
|
验收:
|
|||
|
|
|
|||
|
|
- [x] 模型不能通过自由文本触发数据库写入,服务端只输出白名单 `StewardActionStep`。
|
|||
|
|
- [x] 申请提交动作没有确认时返回 `needs_confirmation`,不会写库。
|
|||
|
|
- [x] 申请提交动作没有 precheck 通过证据时被阻断。
|
|||
|
|
- [x] 保存申请草稿和创建报销草稿通过现有业务服务真实入库,测试覆盖。
|
|||
|
|
- [x] 前端点击可执行 steward action 会真实调用 executor,并把结果回写到会话消息。
|
|||
|
|
- [x] 基础副作用动作有 `client_trace_id` 幂等键、conversation checkpoint 和 pending interrupt 记录。
|
|||
|
|
|
|||
|
|
### Phase 4:checkpoint 与 human-in-the-loop
|
|||
|
|
|
|||
|
|
目标:让 LangGraph 负责暂停、恢复和跨轮状态,而不是只靠前端消息状态。
|
|||
|
|
|
|||
|
|
文件:
|
|||
|
|
|
|||
|
|
- 已创建:`server/src/app/services/steward_graph_action_runtime.py`
|
|||
|
|
- 已复用:`server/src/app/models/agent_conversation.py`
|
|||
|
|
- 已测试:`server/tests/test_steward_action_executor.py`
|
|||
|
|
|
|||
|
|
步骤:
|
|||
|
|
|
|||
|
|
- [x] 设计 `conversation_id -> thread_id` 映射,当前直接以 `conversation_id` 作为 graph action thread。
|
|||
|
|
- [x] 实现基于数据库的 checkpoint,先复用 `AgentConversation.state_json`。
|
|||
|
|
- [x] 在提交审批缺确认时生成 pending interrupt payload。
|
|||
|
|
- [x] 用户确认后用同一 `client_trace_id` / `conversation_id` 继续执行;终态请求会幂等重放。
|
|||
|
|
|
|||
|
|
验收:
|
|||
|
|
|
|||
|
|
- [x] 刷新页面后,后端仍保留当前等待确认的 action checkpoint。
|
|||
|
|
- [x] 同一个 action 不会因为重复点击或重试重复写库。
|
|||
|
|
- [ ] 前端完整恢复 UI 仍需继续把 checkpoint 状态展示为可恢复按钮。
|
|||
|
|
|
|||
|
|
### Phase 5:可观测性与 legacy 收敛
|
|||
|
|
|
|||
|
|
目标:让 agent 规划过程可解释、可测试、可回放,并逐步删除重复手写编排。
|
|||
|
|
|
|||
|
|
文件:
|
|||
|
|
|
|||
|
|
- 修改:`server/src/app/services/agent_traces.py`
|
|||
|
|
- 修改:`server/src/app/models/agent_run.py`
|
|||
|
|
- 修改:`document/development/Agent链路追踪中心/CONCEPT.md`
|
|||
|
|
- 测试:`server/tests/test_agent_traces.py`
|
|||
|
|
|
|||
|
|
步骤:
|
|||
|
|
|
|||
|
|
- [ ] 每个 graph node 写入 trace event:输入摘要、输出摘要、耗时、错误。
|
|||
|
|
- [ ] 前端显示“模型规划中 / 字段判断中 / 等待确认 / 执行动作”阶段。
|
|||
|
|
- [ ] 对 legacy planner 增加废弃标记和删除条件。
|
|||
|
|
- [ ] 删除重复的手写分支前,先保留至少一轮灰度开关。
|
|||
|
|
|
|||
|
|
验收:
|
|||
|
|
|
|||
|
|
- 任何一次用户请求都能从 trace 看出走过哪些 node。
|
|||
|
|
- 删除 legacy 前,LangGraph 路径覆盖当前核心申请/报销链路测试。
|
|||
|
|
|
|||
|
|
## 回退策略
|
|||
|
|
|
|||
|
|
- 环境变量:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
STEWARD_AGENT_RUNTIME=legacy
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
- 回退后:
|
|||
|
|
- `/steward/plans` 使用旧 `StewardPlannerService`。
|
|||
|
|
- 新 action node 和 checkpoint 不应影响 legacy。
|
|||
|
|
- 回退原因必须写入当天工作日志。
|
|||
|
|
|
|||
|
|
## 验证矩阵
|
|||
|
|
|
|||
|
|
每个阶段至少跑:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
docker exec -w /app -e SERVER_VENV_DIR=/tmp/x-financial-server-venv x-financial-local-linux \
|
|||
|
|
timeout 60s /tmp/x-financial-server-venv/bin/pytest -q \
|
|||
|
|
server/tests/test_steward_graph_planner.py \
|
|||
|
|
server/tests/test_steward_planner.py \
|
|||
|
|
server/tests/test_steward_intent_agent.py \
|
|||
|
|
server/tests/test_runtime_chat_service.py
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
涉及前端执行器时补跑:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
node --test web/tests/workbench-ai-intent-planner-model.test.mjs \
|
|||
|
|
web/tests/workbench-ai-application-gate-model.test.mjs \
|
|||
|
|
web/tests/steward-actions-service.test.mjs \
|
|||
|
|
web/tests/steward-plan-message-copy.test.mjs
|
|||
|
|
npm --prefix web run build
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
每次完成后执行:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
git diff --check
|
|||
|
|
docker exec -w /app -e SERVER_VENV_DIR=/tmp/x-financial-server-venv x-financial-local-linux \
|
|||
|
|
/tmp/x-financial-server-venv/bin/python -m pip check
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 不做的事
|
|||
|
|
|
|||
|
|
- 不引入 LangChain 高层 Agent 来替代现有业务服务。
|
|||
|
|
- 不让模型直接调用数据库写入、提交审批或绑定附件。
|
|||
|
|
- 不为了接框架重写申请、报销、OCR、票据夹、审批规则。
|
|||
|
|
- 不在没有测试覆盖时删除 legacy planner。
|
|||
|
|
|
|||
|
|
## 风险与处理
|
|||
|
|
|
|||
|
|
- 模型连通性不稳定:先修 provider 和 backup,再扩大 graph 节点。
|
|||
|
|
- checkpoint 与业务 state 双写不一致:先复用 `AgentConversation.state_json`,不要新增第二个业务状态源。
|
|||
|
|
- action node 副作用重复执行:每个 action 必须有幂等键和执行前状态检查。
|
|||
|
|
- LangGraph 传递依赖影响 WebSocket:当前 `pip check` 通过;后续若流式接口异常,先核对 `websockets` 版本。
|
|||
|
|
- 节点内继续堆大块逻辑:每个 node 只做一类事,超过 300 行先拆文件。
|