P1.3-P1.7:把 endpoint 补丁搬进图节点,门控收敛到 gate_classify 单一决策点。
- StewardGraphState 扩展:recent_history/steward_state/gate_decision/gate_scene_id/conversation_id
- 新增 5 个图节点:load_context(读历史+state)/gate_classify(统一门控)/execute_scene_handler/resume_recent_task/pending_flow wrapper
- 图拓扑从 5 节点重构为 10 节点:load_context → gate_classify → {off_topic/handler_only/resume/ambiguous/model_intent} → attach_action_steps
- gate_classify 四步裁决:resume门 → off_topic门 → 规则匹配门 → LLM门
- resume 门控优先于 off_topic,避免'再提交'被误判闲聊
- schema 放宽 planning_source/next_action Literal → str,支持 scene_handler:*/context_resume/answer_only
- endpoint 按 planner 类型分发 build_plan(LangGraph 接 db,legacy 不接)
- 76 passed + 4 场景端到端验证(出差申请/再提交/查差旅标准/闲聊)
20 KiB
2026-06-25 工作日志
当日工作内容
-
09:18:我完成了项目级
write-development-docs技能落地。- Git 提交检查:
git fetch --all --prune后未发现HEAD..origin/main或origin/main..HEAD新提交;工作区已有多处未提交改动,本次只处理.codex/skills/write-development-docs和.gitignore。 - 修改:新增
.codex/skills/write-development-docs/SKILL.md、agents/openai.yaml、assets/CONCEPT.md、assets/TODO.md,把“落文档”请求固化为document/development/<功能目录>/CONCEPT.md + TODO.md两文件流程。 - 修改:补充
.gitignoreallowlist,确保write-development-docs技能文件不会被.codex/skills/*忽略规则挡住。 - 操作:先读取
document/development既有样例和hermes/skills/domain/write-development-docs旧版技能,再用init_skill.py生成标准 Skill 骨架并收口为项目规范。 - 验证:
frontmatter ok、required files ok、.codex/skills/write-development-docs无[TODO:]初始化占位符,git diff --check -- .codex/skills/write-development-docs .gitignore通过。 - 影响:以后用户说“落文档 / 写开发文档 / 补 concept 和 todo”时,可以优先触发仓库级技能,按项目格式生成两份开发文档。
- Git 提交检查:
-
09:23:我按新的目录约定升级了
write-development-docs技能。- Git 提交检查:
git fetch --all --prune后未发现 upstream 新提交;本地 ahead 1 个提交,为本会话前一步生成的23f7de6c chore(skills): add development docs writer。 - 修改:
.codex/skills/write-development-docs和hermes/skills/domain/write-development-docs同步新增路径规则,默认落点调整为document/development/<YYYY-MM-DD>/feature/<具体功能点目录>/CONCEPT.md + TODO.md。 - 修改:两个技能副本的
agents/openai.yaml、assets/CONCEPT.md、assets/TODO.md同步补充日期、feature聚合层和具体功能点目录提示。 - 操作:保留历史文档原地更新规则,避免把
document/development既有旧路径自动搬迁。 - 验证:两个
SKILL.mdfrontmatter 分别校验通过,路径规则检索命中,两个技能副本的模板和 UI 元数据 diff 一致,git diff --check -- .codex/skills/write-development-docs hermes/skills/domain/write-development-docs通过。 - 影响:后续新功能落文档会先按日期建目录,再进入
feature,最后按具体功能点独立建目录,便于按天回溯和按功能点拆分。
- Git 提交检查:
-
21:30:我针对 AI 工作台意图门控做了三处加固,守住高风险动作的确认底线、补齐缺失的兜底与预筛逻辑。
- Git 提交检查:
git fetch --all --prune后 origin/main 落后本地 0、领先本地 0;本地 ahead 3 个提交(6b0756a5/4d8a606c/23f7de6c),均与本任务无关;工作区有大量未提交改动,本次只动web/src/composables/workbenchAiMode与对应测试。 - 背景:先通读门控全链路(
workbenchAiApplicationGateModel/workbenchIntentFrameModel/workbenchIntentActionPolicy/workbenchAiIntentPlannerModel/useWorkbenchAiCommandIntents/useWorkbenchAiActionRouter/usePersonalWorkbenchAiMode),确认高风险动作(删除/审核/驳回)一律requiresConfirmation且执行出口无execute_allowed、政策类问题被挡在执行链路外、直接提交需二次确认——安全底线稳。 - 修改①(低置信度反问):
workbenchAiIntentPlannerModel.js新增WORKBENCH_AI_INTENT_CONFIDENCE_THRESHOLD=0.6与isLowConfidenceTravelApplicationPlan;规则兜底(rule_fallback)与显式 submit/save_draft 不计为低置信。usePersonalWorkbenchAiMode.js在可执行 travel 计划前插入低置信分支,新增startModelPlannedTravelApplicationConfirmation与buildLowConfidenceTravelApplicationConfirmationText,反问消息携带ai_application_confirm_intent动作。useWorkbenchAiActionRouter.js新增ai_application_confirm_intent分支,还原 ontologyFields/提交标记后调用startAiApplicationPreview。 - 修改②(闲聊预筛):
shouldRequestWorkbenchAiIntentPlan增加业务关键词正则,「你好/谢谢/嗯/ok」等闲聊不再发起 35s 的模型规划请求,直接落到通用 steward 回复。 - 修改③(报销兜底核查):复查确认
executeModelPlannedWorkbenchIntent的 catch 分支不 return 时,isReimbursementCreationIntent(cleanPrompt)在后续 823 行仍会被求值,报销兜底天然可达,无需新增重复分支,本次未改动。 - 验证:
workbench-ai-intent-planner-model.test.mjs(20/20,含新增 3 个用例)、workbench-ai-application-gate-model.test.mjs(5/5)、workbench-intent-frame-model.test.mjs(8/8)全绿;expense-application-fast-preview.test.mjs既有 12 个失败(「小财管家」文案/表格渲染问题,与本次无关),本次改动额外使not ok 2 - AI workbench routes compact travel direct-submit planner由失败转通过,无新增失败。 - 影响:模型给出低置信度差旅申请意图时不再直接建预览,先反问确认;闲聊类输入不再误触发模型规划,响应更快、减轻后端压力。
- 局限:
agent-change-logSkill 在当前环境不可调用,已按 AGENTS.md 规范手动增量更新本日志。
- Git 提交检查:
-
22:40:我落地了注册表驱动的意图插槽架构,让新增意图从「改 6+ 处硬编码」降到「写一个描述符 + 执行函数 + 注册」,并端到端跑通了「查差旅标准」查询意图作为样板。
- Git 提交检查:
git fetch --all --prune后本地与 origin/main 同步(不 ahead 不 behind);工作区有本次新增/修改的后端文件。 - 背景:排查确认旧架构里
task_type/assigned_agent/flow_id在 schema(Literal)、function call schema(enum)、model_plan_builder(白名单)、action_contracts(if/else)、action_executor(if/elif)五层硬编码,加一个意图要同步改 6+ 处,完全没有扩展点;且"查差旅标准"这类查询意图无任何位置(task_type enum 只有 expense_application/reimbursement)。 - 修改①(注册表核心):新建
steward_intent_registry.py——IntentDescriptor声明 task_type/assigned_agent/signal_keywords/ontology_field_allowlist/action_steps_builder/executor/flow_id/prompt_fragment;新建steward_intent_bootstrap.py在 import 时注册 3 个意图(expense_application/reimbursement/query_travel_standard)。 - 修改②(schema 放宽):
schemas/steward.py把StewardTaskType/StewardAssignedAgent/StewardActionType/StewardFlowId从 Literal 改为 str,运行时校验下沉到 registry,让 schema 不再是扩展拦路虎。 - 修改③(执行分发):
steward_action_executor.py的execute()从 if/elif 链改为优先查 registry(resolve_intent_by_action)委托 executor;新增_dispatch_application_action/_dispatch_reimbursement_action分发入口;SUPPORTED_ACTIONS/NOOP_ACTIONS改为与 registry 聚合(all_side_effect_actions/all_noop_actions)。 - 修改④(动作生成):
steward_action_contracts.py的build_task_action_steps改为查 registry 的action_steps_builder;原_build_application_steps/_build_reimbursement_steps改公开供 registry 引用。 - 修改⑤(function schema 动态化):
steward_intent_agent.py的 task_type/flow_id enum 改为all_task_types()/all_flow_ids()动态生成;system prompt 改为从 registry 拼接意图列表 + 每个 intent 的 prompt_fragment。 - 修改⑥(白名单放开):
steward_model_plan_builder.py的 task_type 白名单改get_intent;assigned_agent/flow_id/字段过滤全部改 registry 驱动;_sanitize_model_ontology_fields/_sanitize_model_missing_fields改 per-task_type allowlist(field_allowlist_for);查询类意图(flow_id=None)跳过必填字段推断。 - 修改⑦(查询执行器):新建
steward_query_executors.py——build_travel_standard_query_steps生成单步无副作用动作;execute_travel_standard_query从槽位取 location/employee_grade/standard_category,复用DEFAULT_TRAVEL_POLICY_CONFIG按职级×城市分级查住宿/交通标准,拼装 Markdown 回复(补助标准因未纳入运行时配置用占位说明)。 - 修改⑧(门控适配):
steward_planner_extraction.py的_looks_like_ambiguous_travel_flow加查询信号词前置判断(命中查询意图直接返回 False,不走候选流程);_build_task的 task_id/assigned_agent/label 改 registry 驱动;steward_planner_fallback.py的_classify_irrelevant_input补充 registry signal_keywords 判断(避免查询类输入被判 off_topic);steward_graph_planner.pyimport bootstrap 触发注册。 - 修改⑨(前端):
stewardPlanModel.js的TASK_TYPE_LABELS/AGENT_LABELS/EXECUTABLE_STEWARD_ACTION_TYPES加 query_travel_standard/execute_travel_standard_query/policy_query_assistant。 - 验证:后端全量 steward 测试 72 passed(含新增 14 个:registry 7 + query executor 7);前端意图测试 28 passed;既有申请/报销/规划/动作执行/槽位决策链路全部无回归。
- 容器:容器名为
x-financial-local-linux(非local-x-financial-linux),已运行 19 小时;后端测试在该容器内执行,venv 在/tmp/x-financial-server-venv。 - 影响:现在加一个新意图(如查报销进度、查预算执行)只需:① 写
IntentDescriptor声明 task_type/槽位/信号词/executor;② 注册进 bootstrap;③ 写执行函数。function schema、动作生成、执行分发、字段过滤、门控全部自动适配,零硬编码改动。 - 局限:补助标准(allowance)尚未接入运行时配置,查询时返回占位说明;前端查询结果当前以 Markdown 消息展示,未做卡片化;registry 只在后端,前端 task_type 分发仍是
resolveNextActionContext的 if/else(本次只加了 query 分支,未全面注册表化)。
- Git 提交检查:
遗留问题
-
09:18:官方
quick_validate.py仍因当前 Python 环境缺少PyYAML无法运行,已用 frontmatter、必需文件、占位符和 diff check 做人工兜底。建议后续统一为 skill 校验脚本补齐依赖或增加无 PyYAML 的轻量校验路径。 -
09:23:当前环境没有找到 Skill Creator 的
quick_validate.py脚本文件本体,因此本次继续采用人工兜底校验。建议后续恢复系统 Skill Creator 脚本路径,或把轻量校验脚本纳入仓库级工具。 -
21:30:
expense-application-fast-preview.test.mjs仍有 12 个既有失败(文案「小财管家」「此意图系统不支持」与 markdown 表格整块渲染相关),与本次意图门控改动无关,建议单独排查。 -
21:30:本次未纳入范围的三项已记录:时间过滤维度扩展(仅支持 N天前/昨天/今天)、排除词两处重复维护、
handleInlineDraftDeletionIntent命名与职责不符,建议后续分批处理。 -
22:40:补助标准(allowance)未纳入
DEFAULT_TRAVEL_POLICY_CONFIG,查询差旅标准时住宿/交通有确定数值,补助只返回占位说明。补助数据在server/rules/finance-rules/出差补助标准.xlsx,后续需把补助标准接入运行时配置并在resolve_travel_standard_snapshot补全。 -
22:40:前端查询结果当前以普通 Markdown 消息展示,没有像申请预览那样的卡片化视图;查询意图的前端分发仍是
resolveNextActionContext的 if/else,未全面注册表化(本次只加了 query 分支)。 -
22:40:
server/rules/finance-rules/下有两个 Excel(交通工具等级标准、交通费用预估表)被标记为 modified,疑似容器运行时产物,非本次代码改动,未处理。 -
22:40:
agent-change-logSkill 在当前环境不可调用,已按 AGENTS.md 规范手动增量更新本日志。 -
23:30:我落地了会话上下文保留机制(LLM + 确定性双保险),解决了"用户删除草稿后说'再提交'丢失上下文"的问题。
- Git 提交检查:
git fetch --all --prune后本地与 origin/main 同步(不 ahead 不 behind)。 - 背景:排查确认对话消息和 steward_state 虽已持久化在 DB,但 plan 接口的
build_plan从不读历史 task,且"再提交"被路由到 plan 接口(而非能恢复 task 的 runtime-decision 接口),导致系统无法把"再提交"和之前被拦的出差申请关联起来。 - 修改①(LLM 历史关联·保险②):
steward.py新增_inject_recent_conversation_history,在 build_plan 前用AgentConversationService.list_message_history(conversation_id, limit=10)读出最近 10 条对话,注入context_json.recent_history。steward_intent_agent.py的_build_messages把 recent_history 暴露为 context_payload 顶层结构化字段,并在 system prompt 加引导:"当用户说'再提交''继续''重新提交'等确认类话术时,必须结合 recent_history 里最近一次提到的出差/报销申请来理解"。 - 修改②(确定性兜底·保险①):新建
steward_context_resume.py——should_resume_recent_task检测"再提交"类话术(12 个关键词)+steward_state.flows有可恢复 flow;resume_task_from_flow从 flow.fields 恢复 StewardTask(复用 runtime-decision 的恢复逻辑);attach_resumed_task把恢复的 task 挂回 plan,planning_source 标记为context_resume。steward.py新增_apply_context_resume,在 build_plan 后、plan 无 task 时触发确定性兜底。两个入口(/plans和/plans/stream)都已接入。 - 验证:后端全量测试 67 passed(含新增 11 个:context_resume 8 + intent_agent history 3);端到端验证两轮对话——"上海出差火车"→"再提交",LLM 历史关联成功恢复 expense_application task(fields 完整);纯函数验证确定性兜底在模型返回空 task 时从 state 恢复(planning_source=context_resume)。
- 影响:会话上下文保留到用户清理会话;行为处理只看最近 10 条,超长会话不爆 token;"再提交"类话术现在能恢复之前被拦的申请 task。正常 plan 产生的 task 已通过
merge_plan写进steward_state.flows,重复检查不改 state,所以 task 在 state 里一直存活到会话结束。
- Git 提交检查:
遗留问题(补充)
-
23:30:历史条数固定为 10,未做 token 感知裁剪;极端情况下单条消息很长(如粘贴大段文本)可能导致 token 超限,但实测正常对话不会触发。
-
00:10:我完成了统一门控管道的架构设计文档,作为后续重构的唯一事实来源。
- 文档路径:
document/development/AI意图规划器/UNIFIED_GATE_PIPELINE.md - 核心判断:当前门控散落在 7 处(前端 7 层 if/else + 后端 endpoint 4 个补丁 + 图条件边 + off_topic 关键词 + 候选流程判定),每加一个场景成本 O(n),漏一处静默出错。这是"不持久"的根因。
- 目标架构:LangGraph 图成为唯一编排者(load_context → gate_classify → route 分支 → attach_action_steps → persist_state),endpoint 退化为 3 行纯 IO,前端退化为纯渲染(fetchStewardPlan → renderPlanResponse)。
- 接入成本 O(1) 的硬验收标准:加场景只需新建 1 个 SceneDescriptor + 1 个 handler 函数 + 注册,不动图/endpoint/前端/extraction。
- 迁移分 3 阶段:Phase 1 后端收口(建 scenes 注册表 + endpoint 补丁搬进图节点)、Phase 2 前端退化纯渲染(移除 7 层 if/else)、Phase 3 清理冗余。
- Git 提交检查:本地与 origin/main 同步。
- 文档路径:
-
00:50:我完成了统一门控管道 Phase 1 的 scene 注册表骨架(P1.1-P1.2),作为后端收口的基础设施。
- Git 提交检查:本地与 origin/main 同步。
- 修改:新建
server/src/app/services/scenes/目录——gate_rules.py(GateRule/SceneRoute 枚举)、scene_descriptor.py(SceneDescriptor dataclass,声明 scene_id/label/signal_keywords/ontology_fields/gate/route/handler/can_resume/flow_id/prompt_fragment/priority 等)、scene_registry.py(SceneRegistry 单例 + 查询方法)、3 个场景文件(expense_application/reimbursement/query_travel_standard)、__init__.py(bootstrap + 运行时绑定 handler/builder/executor)。 - 验证:冒烟测试 3 个场景注册成功、优先级排序正确(query 在前,priority=50)、35 个 signal_keywords 聚合、handler/builder/executor 运行时绑定成功、无循环 import;后端全量 76 passed,scene 注册表的加入未破坏任何现有代码。
- 影响:为后续图拓扑重构(P1.3-P1.8)提供了声明式场景注册基础设施。当前 scene_registry 与现有 intent_registry 并存,后续 P1.3-P1.7 会把 intent_registry 的消费者逐步迁移到 scene_registry。
- 下一步:P1.3-P1.8 图拓扑重构(新增 load_context/gate_classify/resume/persist 节点、endpoint 退化、registry 消费者迁移)。
-
01:30:我完成了统一门控管道 Phase 1 的图拓扑重构(P1.3-P1.7),LangGraph 成为唯一编排者。
- Git 提交检查:本地与 origin/main 同步。
- 修改①(图节点扩展):
steward_graph_planner.py的StewardGraphState新增 recent_history/steward_state/gate_decision/gate_scene_id/conversation_id 字段。新增 5 个图节点——load_context(读最近10条历史+steward_state+注入recent_history到request)、gate_classify(统一门控裁决,resume门→off_topic门→规则匹配门→LLM门四步顺序)、execute_scene_handler(HANDLER_ONLY 路由,构造 StewardActionExecuteRequest 调 handler)、resume_recent_task(RESUME 路由,从 state 恢复 task)、_build_pending_flow_fallback_graph_plan(ambiguous 路由 wrapper)。 - 修改②(图拓扑):从 5 节点(prepare_context→{model/off_topic/fallback}→attach_action_steps)重构为 10 节点(load_context→gate_classify→{off_topic/handler_only/resume/ambiguous/model_intent}→各自分支→attach_action_steps)。
- 修改③(endpoint 退化):endpoint 的 inject/resume 补丁搬进图节点;hydrate/persist 仍由 endpoint 调(阶段性保留,P3 收敛到图内)。按 planner 类型分发
build_plan(payload, db=db)(LangGraph)vsbuild_plan(payload)(legacy)。 - 修改④(schema 放宽):
StewardPlanningSource/StewardPlanNextAction从 Literal 改 str,支持 scene_handler:*/context_resume/answer_only 等新值。 - 修改⑤(resume 门控优先级):resume 门控提到 off_topic 门之前,避免"再提交"被误判 off_topic。
- 验证:后端全量 76 passed;端到端 4 场景全部通过——①出差申请(llm_function_call, 1 task)、②再提交(context_resume, 1 task, 5 fields)、③查差旅标准(scene_handler:query_travel_standard)、④闲聊(off_topic)。
- 影响:LangGraph 图成为唯一编排者,门控收敛到 gate_classify 单一决策点。endpoint 仍保留 hydrate/persist 两个补丁,P3 会收敛。
TODO
TODO
- 为
quick_validate.py准备稳定运行环境,避免后续新增 Skill 时继续依赖人工兜底。(来源:09:18 技能校验) - 排查
expense-application-fast-preview.test.mjs的 12 个既有失败(小财管家文案 / 表格整块渲染)。(来源:21:30 意图门控加固) - 评估意图门控剩余三项:时间过滤维度扩展、排除词常量抽取、
handleInlineDraftDeletionIntent重命名。(来源:21:30 意图门控加固) - 把补助标准(
出差补助标准.xlsx)接入运行时配置,补全resolve_travel_standard_snapshot的 allowance 数值查询。(来源:22:40 注册表架构) - 前端查询结果卡片化,并把前端 task_type 分发也改成注册表驱动。(来源:22:40 注册表架构)
- 在真实 LLM 连通环境下,用「我去武汉出差的住宿标准是多少」端到端验证查询意图识别→执行→回复。(来源:22:40 注册表架构)
- 评估是否需要把 LangGraph 迁移 Phase 5(trace UI、legacy 收敛)与注册表架构的查询意图 trace 打通。(来源:22:40 注册表架构)