116 Commits

Author SHA1 Message Date
caoxiaozhu
a0f6d9f702 chore: 更新 .env.example、财务规则表与 AI 意图规划开发文档 2026-06-24 21:59:15 +08:00
caoxiaozhu
bb681aa1f3 chore(repo): 移除误跟踪的 egg-info 构建产物并新增忽略规则
server/src/x_financial_server.egg-info/ 为 uv/pip 构建产物,此前被误跟踪。
本次 git rm --cached 移除跟踪(本地保留),.gitignore 新增 *.egg-info/ 规则避免后续误入库。
2026-06-24 21:59:09 +08:00
caoxiaozhu
bc560145a4 feat(web): AI 工作台意图规划与规划思考模型
- 新增 workbenchAiIntentPlannerModel,基于 LLM function_call 解析建单/草稿/提交意图,区分 model 与 rule_fallback 来源
- 新增 workbenchAiPlanningThinkingModel 合并规划思考事件流,按 eventId 去重合并
- application gate/preview 模型接入意图规划,usePersonalWorkbenchAiMode/useWorkbenchAiStewardFlow/useWorkbenchAiActionRouter 链路适配,支持上下文提交
- steward 服务与 stewardPlanModel 适配新动作结构,receipt-folder-view 微调样式
- 新增 intent-planner-model/application-context-submit/steward-actions-service 测试,更新 gate-model/action-router/plan-message-copy/fast-preview 测试
2026-06-24 21:58:46 +08:00
caoxiaozhu
5311c99d69 refactor(server): steward 决策链路改用 LangGraph 编排
- 新增 StewardGraphPlannerService,用 LangGraph 状态图编排意图识别→流程判断→模型/规则分支→兜底,替代原 planner 内线性调用
- 新增 StewardGraphRuntimeService 编排运行时决策与槽位决策;StewardActionContracts/Executor 统一动作合约与执行
- steward_intent_agent/application_fact_resolver/runtime_chat 适配图执行器,config 暴露图相关开关
- pyproject/uv.lock 新增 langgraph 依赖
- 新增 graph_planner/graph_runtime/action_executor 测试,更新 intent_agent/planner/fact_resolver/runtime_chat/reimbursement 测试
2026-06-24 21:58:35 +08:00
caoxiaozhu
545b31d32f chore(env): docker-compose 端口与服务配置微调并更新规则表与日志
- docker-compose(.full).yml 与 start.sh 微调端口/服务配置
- AGENTS.md 同步更新协作规范
- 更新交通/通信/差旅等财务规则表,补 2026-06-24 work-log
2026-06-24 12:36:03 +08:00
caoxiaozhu
8417a9f542 feat(web): 设置中心缓存管理与文件预览资产工具
- 新增 documentPreviewAssets 工具,统一从 URL/Blob/File 推断预览类型(image/pdf/file/unsupported)
- SettingsView/SettingsView.js/settingsModelHelper 新增系统缓存管理区块,调用 /settings/cache/clear 并展示清理结果;useSettings/services 适配
- WorkbenchAiFilePreviewDialog/useWorkbenchAiFilePreview 接入预览资产工具,workbenchAiComposerModel 调整文件处理
- ReceiptFolder/LogDetailView/DigitalEmployeeWorkRecords/travelReimbursementAttachmentModel 配套适配
- 新增 settings-cache-management-section 测试,更新 settings-llm/rendering/receipt-folder-view/composer-components/attachment-association 测试
2026-06-24 12:35:59 +08:00
caoxiaozhu
9a5ed0e94a feat(server): 系统缓存清理接口与 OCR 文本层兜底增强
- 新增 system_cache 模块与 POST /settings/cache/clear,管理员可一键清理 OCR 结果/运行时配置/模型失败冷却/知识库索引/地点语义等进程内缓存
- 各服务暴露 clear_*_cache 方法(ocr/runtime_settings/runtime_chat/knowledge/application_location_semantic),SettingsCacheClearRead 汇总清理项
- OCR 转图片失败时尝试用 PDF 文本层兜底构建识别文档(有效字符≥8),并写结果缓存;OcrService 暴露 clear_result_cache
- receipt_folder 车票过滤补充身份证号关键词,附件文档/操作/展示模块同步适配
- 新增 system_cache_endpoints 测试,更新 openapi_schema/ocr/receipt_folder/attachment_association_jobs 测试
2026-06-24 12:35:51 +08:00
caoxiaozhu
50d2dc579a style(web): 微调 AI 工作台样式 2026-06-24 10:43:08 +08:00
caoxiaozhu
f9553a6a1a docs: 清理过期计划文档并补全 work-log 与开发/用户文档
- 删除已落地的 improvement-roadmap、superpowers 计划与 ui-mockups 参考稿,删除早期 work-log(2026-05-06~08)
- 新增 2026-05-23 起的 work-log 与 attachment-association-background-job、reimbursement-draft-action-branching 等开发文档及用户文档
- docker-compose(.full).yml 微调服务配置
2026-06-24 10:42:57 +08:00
caoxiaozhu
ee730aa31c feat(web): AI 工作台文件预览/附件关联任务与草稿分支
- 新增 WorkbenchAiFilePreviewDialog 附件预览对话框及 useWorkbenchAiFilePreview,附件支持点击预览
- 新增 attachmentAssociationJobs/linkedReimbursementDraftJobs 前端服务与对应 composable,接入后台任务轮询与状态展示
- 新增 travelReimbursementDraftBranchModel 草稿分支模型,报销关联门控支持跳过/选择草稿
- PersonalWorkbenchAiMode 及各 composable(expense/document/steward/application-preview/attachment-association)重构适配,WorkbenchAiComposer/FileStrip 样式与交互完善
- DocumentsCenter/ReceiptFolder/TravelReimbursementCreate 等视图及 scripts 重构,风险/差旅规划/审批等工具适配
- 新增/更新前端测试:application-result-card、reimbursement-list-preview-fetch、guided-flow、composer-components 等
2026-06-24 10:42:50 +08:00
caoxiaozhu
0264a4b5b4 refactor(server): user_agent/steward/ocr 等服务重构并适配关联任务
- user_agent 拆分 application/locations/knowledge/response/review 四个子模块,接入申请位置语义与关联草稿分支
- steward planner/runtime/slot/plan_builder 决策链路重构,travel_reimbursement_calculator/orchestrator_expense_query 适配
- ocr/document_preview/document_intelligence/receipt_folder 复用预览与资产缓存,expense_claim_draft_flow/application_handoff 适配
- pyproject.toml 新增依赖,paddleocr bootstrap 脚本与 server_start.sh 调整
- 更新差旅/交通/通信等财务规则表,同步 document_intelligence/ocr/receipt_folder/user_agent 等测试
2026-06-24 10:42:24 +08:00
caoxiaozhu
332f77389d feat(server): 新增附件关联/关联报销草稿后台任务与申请位置语义
- attachment_association_jobs:从票据夹批量关联附件到报销单,识别城市/日期并创建明细项,内存态 job 跟踪
- linked_reimbursement_draft_jobs:基于申请单异步生成关联报销草稿,调用 Orchestrator 编排,区分 succeeded/failed 终态
- application_location_semantics:抽取差旅出发/到达城市、判断具体地址/业务动作等位置语义,供申请单校验复用
- router 注册两个 job 端点,新增对应 job/语义单元测试
2026-06-24 10:42:05 +08:00
caoxiaozhu
d4ff79f326 chore(agent): 新增变更日志/checkpoint skill 与 post-commit hook
- AGENTS.md 新增变更日志 Skill 规范:变更后增量更新 document/work-log,更新前先做 Git 拉取检查
- 新增 .codex/skills 下 agent-change-log、git-checkpoint-commit 两个 skill
- 新增 .githooks/post-commit 与 tools/agent-change-log 自动化脚本,提供提交后最低限度日志追加
2026-06-24 10:41:56 +08:00
caoxiaozhu
93212600eb chore(skills): add git checkpoint commit loop 2026-06-24 09:47:05 +08:00
caoxiaozhu
73966b3a7b refactor: consolidate finance workflow modules 2026-06-23 11:21:18 +08:00
caoxiaozhu
1f40ce3df3 fix(web): 孤儿申请预览消息触发重新生成可编辑表格
useWorkbenchAiApplicationPreviewFlow 识别仅含表格文案但缺 applicationPreview 载荷的孤儿消息,触发重新生成可编辑表格并提示用户,避免提交动作静默失败。
2026-06-23 09:43:29 +08:00
caoxiaozhu
f17098aa58 chore(repo): 移除误跟踪的 expense_claims 运行时票据文件
server/storage/expense_claims/ 下 30 个用户上传票据/预览图/meta 此前在 gitignore 规则生效前被误提交,运行时会持续产生内容变更。
本次 git rm --cached 移除版本跟踪(本地文件保留),配合已有 server/storage/expense_claims/ 忽略规则,避免后续误入库。
2026-06-23 09:43:07 +08:00
caoxiaozhu
8094333e3b style(web): 通知中心列表行布局重构与时间标签格式化
- TopBar 通知行改为 row-main/row-head/row-foot 结构化布局,标题加粗、分类改为 pill、箭头随标题右侧
- formatNotificationTime 改名 formatNotificationTimeLabel,新增 ISO/短日期直通匹配与超长截断兜底
- 更新 sidebar-document-unread-dot 测试
2026-06-23 09:42:56 +08:00
caoxiaozhu
0122f3b250 chore(rules): 更新交通/通信/差旅/出差等财务规则表 2026-06-23 09:42:43 +08:00
caoxiaozhu
dc4cad2baa chore(env): WEB_PORT 统一回退为 5173 并烟雾检查改为可开关
- .env.example/docker-compose(.full).yml WEB_PORT 默认值 5273→5173(Vite 默认),CORS_ORIGINS 同步
- docker-compose 注入 WEB_PORT/SERVER_PORT 环境变量,健康检查端口随之更新
- start.sh 新增 SERVER_SMOKE_CHECK_ENABLED 开关,默认关闭烟雾检查,仅健康探测
- web/web_start.sh 适配端口
- .gitignore 补充忽略 tmp/ 运行时目录
2026-06-23 09:42:40 +08:00
caoxiaozhu
e725b7f19c feat(web): 票据夹资产缓存接入与 AI 工作台附件流程完善
- ReceiptFolderView 删除票据后提示已关联附件副本保留,接入 useToast;fetchReceiptFolderAsset 加 no-store 避免预览缓存
- PersonalWorkbenchAiMode 附件区/对话气泡适配资产缓存,personal-workbench-ai-mode.css 调整布局
- usePersonalWorkbenchAiMode/useWorkbenchAiApplicationPreviewFlow/useWorkbenchAiAttachmentAssociationFlow/useWorkbenchAiStewardFlow 完善附件草稿选择与关联流程
- travelRequestDetailSmartEntryRecognition 智能识别增强,AppShellRouteView/PersonalWorkbenchView/useApplicationPreviewEditor/useTravelReimbursementSubmitComposer 等配套适配
- 新增 expense-attachment-draft-selection、receipt-folder-asset-cache、travel-request-detail-smart-entry-recognition 测试,更新 attachment-association-confirmation、expense-application-fast-preview、workbench-ai-mode-switch 测试
2026-06-23 09:42:13 +08:00
caoxiaozhu
84a8998e59 feat(server): 票据文件夹资产缓存与文档预览统一生成
- 新增 document_preview 模块,DocumentPreviewAssets 统一处理 data URL 解码、pdftoppm PNG 预览生成(poppler-data 编码)、renderer_id 标识
- receipt_folder 服务复用预览生成,缓存票据资产并提供清理;删除票据时保留已关联报销单的附件副本
- document_intelligence 新增票据预览/资产缓存接入与字段提取增强;ocr 抽取复用预览工具,附件分析/文档/操作/展示四个子模块同步适配
- receipt_folder 端点补充资产缓存头,补/扩 document_intelligence、ocr_endpoints、ocr_service、receipt_folder_service、reimbursement_endpoints 测试,新增 attachment_analysis 回归测试
2026-06-23 09:42:00 +08:00
caoxiaozhu
bc743adef3 chore(rules): 更新公司通信费报销规则表 2026-06-22 15:56:13 +08:00
caoxiaozhu
ded8b39ccb feat(web): 申请单预览编辑器增强与报销流程细节适配
- useApplicationPreviewEditor 扩展字段编辑与校验,useTravelReimbursementApplicationPreviewDateEditor 微调日期处理
- travelReimbursementExpenseQueryModel/reimbursements 服务/expenseApplicationPreview 适配工号/邮箱字段与关联动作
- useWorkbenchAiApplicationPreviewFlow/usePersonalWorkbenchAiMode 接入关联门控后的预览流转
- TravelReimbursementCreateView 调整入口,TravelReimbursementMessageItem 适配
- 新增 expense-application-fast-preview 测试,更新 attachment-association-confirmation、review-drawer-switch 测试
2026-06-22 15:56:06 +08:00
caoxiaozhu
ba444a514f feat(web): 报销单新增关联申请单门控与草稿检测流程
- 新增 travelReimbursementAssociationGateModel,查询可关联申请单/草稿报销单并生成跳过/选择/单独新建动作,区分差旅费与业务招待费类型
- travelReimbursementApplicationLinkModel 补充 buildLinkedApplicationReferenceIndex/buildRequiredApplicationActions 等关联构建逻辑
- useTravelReimbursementSuggestedActions 接入 select_required_application/skip 系列动作,'我要报销'入口改为先走关联门控
- useWorkbenchAiActionRouter 新增 SKIP_REQUIRED_APPLICATION_LINK/SKIP_REIMBURSEMENT_DRAFT_CHECK 动作分发
- useWorkbenchAiExpenseFlow 暴露 startAiReimbursementAssociationGate,stewardPlanModel 待处理流程适配
- 新增 workbench-ai-action-router、workbench-ai-reimbursement-association-gate 测试并更新 guided-flow、steward-plan 测试
2026-06-22 15:55:59 +08:00
caoxiaozhu
aa965da69d feat(server): 报销单输出工号/邮箱并扩展申请人邮箱前缀匹配
- ExpenseClaimRead 新增 employee_no/employee_email 字段,ExpenseClaim 模型补对应只读属性
- expense_claim_access_policy 在姓名匹配未果时,按 candidate@% 邮箱前缀匹配 Employee.email,命中唯一记录即返回
- test_backend_pagination/test_expense_claim_service 补充工号/邮箱字段断言与邮箱前缀匹配用例
- 更新公司通信费报销规则表
2026-06-22 15:55:48 +08:00
caoxiaozhu
1b04ee1c4c fix(web): restore travel detail child component styles 2026-06-22 13:34:12 +08:00
caoxiaozhu
103f225f54 chore(rules): 更新差旅/交通/通信等财务规则表 2026-06-22 12:02:11 +08:00
caoxiaozhu
e42dedaba1 docs: 同步 Docker 编排说明并补充重构计划与 UI 参考
- README 与 docker/README 更新双 compose 文件说明:docker-compose.yml 仅主应用、docker-compose.full.yml 完整栈
- 新增 docs/superpowers/plans 800 行重构实施计划,规划前后端代码体量护栏与按职责拆分路径
- 新增 docs/ui-mockups 附件关联企业版 UI 参考稿
2026-06-22 12:02:08 +08:00
caoxiaozhu
607e127f59 chore(docker): 拆分主应用编排与完整本地栈
- 新增 docker-compose.full.yml:编排 main+postgres+qdrant+onlyoffice 完整本地开发栈,依赖与 DATABASE_URL 由 compose 注入
- docker-compose.yml 精简为仅启动主应用,ONLYOFFICE/QDRANT 相关变量改为空值占位,便于复用外部依赖
- docker-compose.postgres.yml 主应用补充 POSTGRES_*/DATABASE_URL 环境变量
2026-06-22 12:02:03 +08:00
caoxiaozhu
6d33ba5742 refactor: enforce 800 line source limits 2026-06-22 11:58:53 +08:00
caoxiaozhu
08a4fa3577 style(web): AI 工作台附件卡片样式与交互适配
- personal-workbench-ai-mode.css 新增 workbench-ai-file-card 系列样式,file-strip 改为 flex-wrap 左对齐排布卡片,移除按钮样式随卡片重构
- workbench-ai-mode-switch 测试补充附件卡片相关断言
2026-06-21 23:24:36 +08:00
caoxiaozhu
d660a961fb feat(web): AI 工作台附件改为卡片化展示并支持单项移除
- PersonalWorkbenchAiMode 附件区由计数条改为按类型图标/名称/类型标签的卡片列表,支持单项移除(removeAiModeFile),复用 buildFileIdentity 作为 key
- resolveAiComposerFileType 按 pdf/图片/表格/文档/压缩包/文件归类,分别对应图标与色调
- .gitignore 补充忽略 server/storage/receipt_folder/ 运行时票据存储目录
2026-06-21 23:24:16 +08:00
caoxiaozhu
669d22e71f feat(web): 差旅领导意见事件结构化与申请审批信息增强
- applicationApproval 新增按日期/时间/审批角色拆分格式化,buildLeaderApprovalEvents 补充 dateLabel/timeLabel/roleLabel 字段
- TravelRequestDetailView 领导意见事件改为日期+时间+审批人结构化展示,travel-request-detail-view.css 重构对应样式
- travelReimbursementAttachmentModel 微调附件标识,同步更新 application-approval-info、travel-request-detail-leader-approval、attachment-association-confirmation 测试
- 更新公司通信费报销规则表
2026-06-21 23:24:09 +08:00
caoxiaozhu
88e91a5900 feat(ocr): PDF 文本层可用时跳过 worker 调用并补装 poppler-data
- OcrService 提取 PDF 文本层后若有效字符达到阈值,直接构建文档并写入结果缓存,不再触发 OCR worker,仅无文本层时才解析 python_bin/worker_path 调用 worker
- _build_text_layer_document 复用 AggregatedOcrDocument 聚合文本层片段,_has_usable_pdf_text_layer 基于 meaningful_char_count 判定
- docker-compose 与 paddleocr bootstrap 脚本补装 poppler-data,保证 PDF 文本层抽取的中文编码正确
- 新增文本层直取与运行时依赖两项 ocr_service 单测
2026-06-21 23:23:59 +08:00
caoxiaozhu
1986b0d945 style(web): 移除顶栏 AI 快捷操作区并优化差旅领导意见事件样式
- TopBar 移除 AI 模式下的公司切换/AI 模式切换快捷操作块及 showAiModeUtilityActions 计算属性,清理 top-bar.css 对应样式
- TravelRequestDetailView 领导意见事件重构为状态/意见/审批人结构化布局,travel-request-detail-view.css 补充对应样式
- 同步更新 topbar-ai-mode-switch、ai-sidebar-rail-mode、travel-request-detail-leader-approval 测试
2026-06-21 22:56:34 +08:00
caoxiaozhu
24b5b71b0f feat(web): 差旅申请详情进度 viewer 与审批/加载态组件增强
- 新增 requestProgressViewer,申请单在直属领导审批视角下将当前步骤展示为'等待批复',travel-request-detail/app-shell/useRequests 接入
- TravelRequestApprovalDialog 增强审批交互,TableLoadingState 补充表格加载占位,ConfirmDialog 扩展确认对话框能力
- useAppShell/useRequests/AppShellRouteView 配套适配申请详情跳转与会话状态
- 同步更新 requestProgressSteps、travel-request-detail-leader-approval、assistant-session-draft-delete、documents-center-status-filter、app-shell-financial-assistant-entry、request-progress-viewer 等测试
2026-06-21 22:49:58 +08:00
caoxiaozhu
8b3495455b feat(web): AI 文档详情引用解析与查询卡片增强
- 新增 aiDocumentDetailReference,统一解析 #ai-open-document-detail / #ai-open-application-detail 引用,兼容 A/R/D 短格式与 AP-/RE-/AD- 旧格式单号,提供 isBusinessDocumentReference 判定
- aiDocumentQueryModel 文档卡片接入详情引用,按申请单/报销单生成对应 href,HTML 渲染器识别单据记录表格并生成卡片链接
- PersonalWorkbenchAiMode 处理文档详情点击跳转,卡片样式重构为结构化布局并更新背景资源
- expenseApplicationPreview 补充事由字段,同步新增/更新 ai-document-detail-reference、document-query-model、html-renderer、workbench-ai-mode 等测试
- 更新公司通信费报销规则表
2026-06-21 22:49:53 +08:00
caoxiaozhu
3b74a330a3 feat(web): AI 文档查询卡片重构与单号判定统一
- documentClassification 抽出 isApplicationDocumentNo,统一兼容 AP-/APP- 旧格式与 A+8 新格式,aiDocumentQueryModel 复用
- aiDocumentQueryModel 文档卡片改为结构化字段布局(单据类型/金额/申请人/编号/操作),新增查询范围摘要区,渲染走 HTML 信任块
- AppShellRouteView/useAppShell/useRequests/detailAlerts/riskVisibility 等差旅详情模型适配单号判定
- 同步更新 ai-document-query-model/workbench-ai-mode-switch 测试,新增 document-classification 测试
2026-06-20 22:04:37 +08:00
caoxiaozhu
8158716e23 test(server): 适配 A/R/D 紧凑单号格式
- approval_routing/service/user_agent 测试中报销单查询统一兼容 RE- 旧格式与 R+8 新格式,申请单单号断言改为短格式
- generate_claim_no 用例重命名为短前缀校验,正则改为 R[A-HJ-NP-Z2-9]{8}
- 同步更新差旅/交通/通信等财务规则表
2026-06-20 22:04:31 +08:00
caoxiaozhu
0cda750ff0 feat(web): AI 工作台会话与文档卡片渲染增强
- aiConversationHtmlRenderer 识别单据记录类表格并渲染为卡片列表,新增删除申请单详情的禁用占位链接
- aiWorkbenchConversationStore 增加草稿删除后会话链接失效处理,避免点击已删除单据跳转
- aiApplicationPreviewActions 调整提交/草稿调用路径,PersonalWorkbenchAiMode 接入新的会话存储与渲染
- ConfirmDialog/TravelRequestDeleteDialog/useAppShell/AppShellRouteView 配套适配,同步更新相关前端测试
2026-06-20 21:44:16 +08:00
caoxiaozhu
81e990ab72 feat(server): 申请单支持草稿保存并统一删除权限口径
- user_agent_application 新增草稿分支:识别'保存草稿/存草稿/先保存'等意图,复用可编辑记录更新或建草稿,提交前单据重叠仍拦截
- 草稿态返回单号与待提交提示,submit 仅在确认提交分支触发,避免草稿进入审批流
- reimbursements 删除接口文案与判定统一为系统管理员可删、申请人删自有草稿/退回单,申请单判定改用 is_application_claim_no
- 更新财务规则表与 reimbursement 端点测试
2026-06-20 21:44:12 +08:00
caoxiaozhu
47c6a4bb73 refactor(server): 单号规则收紧为 A/R/D+8 位紧凑格式
- DOCUMENT_NUMBER_PREFIXES 改为 A/R/D,新增短格式与旧格式正则并存识别,提取正则加边界锚定避免误匹配
- build_document_number 去掉时间戳段,统一生成 A+token 等紧凑单号,is_application_claim_no 兼容旧 AP-/APP- 前缀
- access_policy/status_registry/reimbursements/expense_claims/budget_support 统一复用 is_application_claim_no 判定申请单
- 同步 document_numbering 单元测试覆盖新旧两种格式
2026-06-20 21:44:06 +08:00
caoxiaozhu
96c2e1099a feat(web): 统一平台管理员判定与 AI 工作台申请预览动作接入
- authUser 抽出 resolveAuthUserAdminFlag,统一 isAdmin 解析(含 superadmin、role_codes、中英文角色名),accessControl 复用同一逻辑
- 登录态、应用外壳路由、系统状态接入统一管理员判定,LoginView 与相关 composable 配套调整
- AI 工作台申请提交改为调用新的 /application-preview-action 接口,草稿保存仍走 orchestrator;预审模型补充重叠冲突提示与阻断判断
- 同步更新 accessControl/api-request/ai 预览动作等前端测试
2026-06-20 14:42:04 +08:00
caoxiaozhu
729d833edb feat(server): 新增申请核对预览快速建单接口与平台管理员判定统一
- reimbursements 新增 POST /application-preview-action,AI 工作台表格核对后直接走 UserAgentService 建单/提交,免去通用 Orchestrator 编排
- 平台管理员判定统一抽取 PLATFORM_ADMIN_IDENTITIES 常量,identity 与 role_codes 均支持 admin/superadmin,含 header 开关
- docker-compose 镜像补装 openssh-server
- 同步更新差旅/交通/通信等财务规则表与 reimbursements 端点测试
2026-06-20 14:41:59 +08:00
caoxiaozhu
304bbe1fd4 feat(web): 工作台 AI 模式报销预审与文档查询模型拆分
- 新增 aiApplicationPrecheckModel/aiDocumentQueryModel/aiApplicationPreviewActions/aiConversationHtmlRenderer 四个独立模型与服务,按职责从主组件拆出
- PersonalWorkbenchAiMode 接入拆分后的预审、文档查询与 HTML 渲染逻辑,配合 markdown 工具增强结构化展示
- 文档中心与归档筛选、风险可见性、申请预览等工具同步适配,补充对应单元测试
- 新增 AI 文档卡片背景资源
2026-06-20 10:17:37 +08:00
caoxiaozhu
3d69f8501f feat(risk): 申请单阶段风险可见性细化与规则表更新
- 申请单阶段将 policy/trip/amount 类风险对申请人可见、可自行修正,画像/审批流程类仍走领导可见
- 平台风险标记与语义推断统一采用该策略,更新对应单元测试
- 风险规则中 city_mismatch 等城市匹配规则移除 expense_application 阶段,仅保留 reimbursement
- 同步更新交通/通信/差旅/出差等财务规则表
2026-06-20 10:17:18 +08:00
caoxiaozhu
4d04f4e7af chore(gitignore): 忽略 .env 防止敏感配置入库
将 .env 从版本库移除(本地文件保留),并补充 .env.local 等本地变体忽略规则,
避免数据库密码、密钥等敏感配置进入 git 历史。
2026-06-18 22:14:53 +08:00
caoxiaozhu
3131112952 style(web): 调整 AI 模式用户消息气泡布局与引用图标
- 用户消息气泡的操作区与时间右对齐
- 引用按钮图标由 mdi-reply 改为 mdi-format-quote-open
2026-06-18 22:13:09 +08:00
caoxiaozhu
a2f67af13e docs: 新增 X-Financial 改进路线图 2026-06-18 22:12:38 +08:00
caoxiaozhu
0cde1f8990 feat(web): 工作台 AI 模式与差旅/风险建议交互优化
- 新增 PersonalWorkbenchAiMode 组件、AI 侧边栏与 orb 机器人视觉资源
- 新增 aiApplicationDraftModel / aiExpenseDraftModel / aiWorkbenchConversationStore
  及业务准入 aiSidebarBusinessAccess,支撑 AI 模式下的申请与报销草稿
- 顶栏、侧边栏、工作台样式重构,适配 AI 模式切换与响应式布局
- 同步 steward plan/off_topic、差旅报销引导流、风险建议卡片等测试
2026-06-18 22:12:24 +08:00
caoxiaozhu
a6674a1e76 feat(steward): off_topic 场景细分与引导回复
- 将业务无关输入细分为 greeting / meaningless / off_business 三类场景
- 新增 StewardOffTopicAgent,用 function calling 生成管家语气引导回复
- steward endpoint 与 user_agent_application 串联 off_topic 引导话术
- 补充 planner 与 user agent 的 off_topic 覆盖测试
2026-06-18 22:12:10 +08:00
caoxiaozhu
127d603e7d feat(ontology): 仅放行财务业务相关问题的信号校验
- 新增 _has_supported_business_signal,在加载目录前拦截非财务问题并抛错
- 同步重构 ontology 服务测试覆盖业务信号判定分支
2026-06-18 22:12:00 +08:00
caoxiaozhu
3f17619e0c fix(auth): 登录目录就绪幂等化与并发控制
- employee/settings/user_session_metrics 的 ensure_*_ready 改为按 bind 缓存 + 锁,
  避免每次登录重复建表与并发场景下的竞态
- auth 登录链路先查员工再降级触发目录就绪,并吞掉查询期 SQLAlchemy 异常
- 默认管理员账号由 superadmin 迁移为 admin,兼容历史账号回填
- 补充登录降级与设置持久化相关测试
2026-06-18 22:11:53 +08:00
caoxiaozhu
59ba76c74a feat(startup): 服务端启动 bootstrap 与缓存预热
- 新增 STARTUP_BOOTSTRAP_ENABLED / STARTUP_CACHE_WARMUP_ENABLED 配置开关
- lifespan 拆分 bootstrap 步骤并后台线程预热缓存,失败可降级继续启动
- server_start.sh / web_start.sh 扩展 SERVER_PORT、启动与调度开关的 env 覆盖
- bootstrap_paddleocr_mobile.sh 改用 python3 并补充 poppler-utils 依赖
- 补充启动 bootstrap 与 env 覆盖优先级测试
2026-06-18 22:11:37 +08:00
caoxiaozhu
35372c6661 feat(rules): 更新差旅与通信费用等财务规则表 2026-06-18 22:11:13 +08:00
caoxiaozhu
38653fa365 chore(storage): 清理用户历史报销票据附件
移除测试期残留的 receipt_folder 附件与预览文件,后续通过归档目录维护。
2026-06-18 22:11:10 +08:00
caoxiaozhu
c28e99b714 chore(gitignore): 忽略 .nezha/ 与 .omo/ 本地工具目录 2026-06-18 22:11:06 +08:00
caoxiaozhu
43432534d8 feat(steward): 前端支持 off_topic 与引导话术
- assistantSessionScope.js:新增 ASSISTANT_SCOPE_ACTION_FILL_COMPOSER 常量
- assistantSuggestedActionPrefill.js:识别 fill_composer 与 payload.fill_text
- stewardPlanModel.js:normalizeStewardPlan 透传 suggestedPrompts;
  buildStewardPlanMessageText / buildStewardSuggestedActions
  新增 off_topic 分支,按钮填充输入框不提交
- useStewardPlanFlow.js:isPendingStewardActionMessage 排除 off_topic
- steward-plan-off-topic.test.mjs:覆盖 normalize/文案/按钮/兼容路径
2026-06-18 14:15:30 +08:00
caoxiaozhu
cce19e4c40 feat(steward): 拦截业务无关输入返回 off_topic 计划
- schemas/steward.py:StewardPlanResponse 新增 suggested_prompts 字段
- steward_planner.py:新增 STEWARD_BUSINESS_SIGNAL_KEYWORDS 与
  _is_business_irrelevant_input 守卫,在 build_plan 入口前置;
  新增 _build_off_topic_plan 构造 plan_status=off_topic 的引导计划
- steward_intent_agent.py:system prompt 追加业务无关约束
- test_steward_planner.py:覆盖 123/你好/纯标点走 off_topic,
  并验证正常业务输入不受守卫影响
2026-06-18 14:15:20 +08:00
caoxiaozhu
b8915a29c0 chore(storage): 归档用户报销票据附件 2026-06-17 14:39:41 +08:00
caoxiaozhu
4199feb681 test: 同步报销审批流与预算分析测试
- 新增预算审批合并、风险标记去重与占位条目校验用例
- 补充预算分析对当前审核人与财务的可见性断言
- 调整单据删除权限测试以匹配 admin 限制
2026-06-17 14:39:26 +08:00
caoxiaozhu
0fac8b615f feat(web): 优化差旅详情、风险建议卡片与文档中心交互
- 拆分阶段风险建议卡片样式到独立文件
- 完善差旅申请审批对话框与详情视图交互
- 调整文档中心列表共享样式与状态筛选
- 同步应用外壳、视图初始化与系统状态 composables
2026-06-17 14:39:12 +08:00
caoxiaozhu
a3e5295915 feat(rules): 更新财务差旅与通信费用规则表 2026-06-17 14:38:51 +08:00
caoxiaozhu
1f4681f486 feat(claim): 重构报销审批流并收敛风险标记
- 直属领导兼任部门 P8 预算审批人时合并预算审批,直接流转至财务审批
- 预算超过警戒值时强制要求预算管理者填写审批意见
- 新增风险标记去重工具,消除各审核阶段重复风险卡片
- 新增工作流修复 Mixin,纠正重复预算审批阶段的历史数据
- 收紧单据删除权限至 admin,放宽预算分析可见范围至当前审核人
- 提交校验放宽已上传票据条目的 OCR 字段缺失并忽略尾部占位条目
2026-06-17 14:38:07 +08:00
caoxiaozhu
09a66c72cb chore: 将 web 端口由 5173 调整为 5273 2026-06-17 14:37:50 +08:00
caoxiaozhu
0d525fa64c chore: 忽略 .codex-temp 工具临时目录 2026-06-17 14:34:36 +08:00
caoxiaozhu
470f343b29 fix(expense): narrow travel route risk indicators 2026-06-17 09:36:24 +08:00
caoxiaozhu
9f7b8b46a3 Refine travel reimbursement steward flow
Align planner, runtime rules, and policy assets so travel guidance
matches the updated reimbursement workflow.
2026-06-15 22:55:18 +08:00
caoxiaozhu
792741709a fix(claim): align risk advice with expense rows 2026-06-15 20:53:48 +08:00
caoxiaozhu
5747e85acf fix(risk): restore upload-time rule center review 2026-06-15 20:20:55 +08:00
Codex
8b952c9a26 refactor(travel): split reimbursement create workflow
完整修改内容:

- 拆分 TravelReimbursementCreateView:提取审核面板纯模型、消息操作、建议动作处理、生命周期 watcher/UI 映射、小财管家运行时、续办流程和运行时文本模型,减少主组件继续堆叠业务分支。
- 调整申请预览链路:新增本地申请意图 gate,完善复杂差旅申请的大模型复核判断、交通方式缺失/候选识别、规则中心交通费用预估合并和申请冲突处理。
- 优化小财管家流程:抽出 steward typewriter 分段策略,避免 Markdown 表格逐字闪烁;补齐跨助手 carry、字段补齐续办、文本确认提交和行程规划推荐动作。
- 调整消息与样式:移除申请预览日期 chip 样式,收敛申请卡片/报销草稿消息的展示与复制、朗读、反馈入口逻辑。
- 更新测试:将源码锚点迁移到新模块,覆盖申请预览、提交确认、小财管家续办、引导流和审核抽屉相关断言。

验证:

- node --check web/src/views/scripts/TravelReimbursementCreateView.js 及新增拆分模块
- npm --prefix web run build
- node --test web/tests/expense-application-fast-preview.test.mjs web/tests/expense-application-submit-rich-confirm.test.mjs web/tests/travel-reimbursement-guided-flow.test.mjs

说明:

- 后端/规则/容器配置/Audit 页面等工作区已有改动未纳入本提交。
- 容器内后端定向 pytest 曾运行 timeout 180s /tmp/x-financial-server-venv/bin/pytest -q <相关后端测试>,180 秒超时且超时前已有失败标记,未作为通过项记录。
- TravelReimbursementCreateView 当前仍超过 800 行,后续仍需继续拆分;本提交先把新增职责模块控制在 800 行内,阻止主类/主模块继续膨胀。
2026-06-13 14:53:23 +00:00
336fee9d93 chore: 忽略 .superpowers 工具缓存目录 2026-06-12 09:43:53 +08:00
caoxiaozhu
25724c354f feat: 同步报销流程与工作台改动 2026-06-09 08:32:00 +00:00
caoxiaozhu
e124e4bbcb feat: 报销审批流重构与管家计划全链路贯通
- 重构报销状态注册表、审批流路由与平台风险标记
- 完善管家意图规划器与模型计划构建器全链路
- 新增 OCR Worker 脚本、数据库会话管理与通知状态
- 优化文档中心、日志视图、预算中心与员工管理交互
- 增强工作台摘要、图标资源与全局主题样式
- 补充审批路由、状态注册、OCR 服务与管家规划器测试覆盖
2026-06-06 17:19:07 +08:00
caoxiaozhu
f60cebadb8 feat: 小财管家意图规划与报销提交编排增强
- 完善管家意图识别、模型计划构建与规划器调度
- 重构差旅报销提交编排器与管家计划流程前端交互
- 优化报销消息项样式与文档中心视图
- 新增小财管家与附件上传风险前置复核设计文档
- 补充管家规划器与文档中心测试覆盖
2026-06-04 14:25:14 +08:00
caoxiaozhu
1cbf3fee44 feat: 报销预审会话状态管理与工作台交互增强
- 新增差旅报销会话状态管理与对话模型重构
- 增强风险观测服务与运行时聊天上下文作用域
- 优化工作台图标资源、助理意图识别与摘要工具
- 完善报销创建视图样式与差旅详情页标准调整交互
- 补充风险观测、运行时聊天与报销端点测试覆盖
2026-06-04 11:03:29 +08:00
caoxiaozhu
87da5df91b feat: 风险可见性控制与差旅详情页交互优化
- 新增风险可见性工具函数与风险日趋势图表组件
- 优化差旅请求详情页费用模型与视图交互
- 完善顶部导航栏样式与应用壳路由逻辑
- 补充风险可见性、风险看板与差旅详情测试覆盖
2026-06-03 22:15:45 +08:00
caoxiaozhu
75d5c178e1 feat(workbench): persist topbar notification state 2026-06-03 21:43:35 +08:00
caoxiaozhu
b9826a1985 fix: keep adjusted risks visible to reviewers 2026-06-03 19:14:40 +08:00
caoxiaozhu
0f8bc4071a fix: preserve reviewer risk notice after standard adjustment 2026-06-03 19:10:29 +08:00
caoxiaozhu
cb36d78fa2 fix: 优化顶部导航栏布局与工作台摘要展示并清理旧票据数据 2026-06-03 17:40:52 +08:00
caoxiaozhu
8e2477587f fix: handle risk explanation standard adjustment 2026-06-03 17:31:40 +08:00
caoxiaozhu
67b81a1bd8 fix(workbench): replay profile radar animation 2026-06-03 17:31:12 +08:00
caoxiaozhu
9c24a852e7 fix(workbench): remount expense stats chart on reopen 2026-06-03 17:22:48 +08:00
caoxiaozhu
95956afbc6 fix(notifications): refine bell notification center 2026-06-03 17:16:09 +08:00
caoxiaozhu
c73178b65d fix(documents): move unread notice into bell 2026-06-03 17:05:34 +08:00
caoxiaozhu
8c2f301d85 fix(documents): sort newest rows first 2026-06-03 16:52:49 +08:00
caoxiaozhu
4717ee6086 fix(documents): refine unread badges and mark all read 2026-06-03 16:46:13 +08:00
caoxiaozhu
513ff909f9 fix: remove manual expense detail add action 2026-06-03 16:44:06 +08:00
caoxiaozhu
92198549f6 fix: require explicit transport mode for applications 2026-06-03 16:36:02 +08:00
caoxiaozhu
59d3bf0f00 fix(auth): keep admin out of personal workbench 2026-06-03 16:31:27 +08:00
caoxiaozhu
04f0951b3d fix: restrict application linking for reimbursement drafts 2026-06-03 16:28:09 +08:00
caoxiaozhu
8887cf5a27 fix(workbench): stretch profile tag card 2026-06-03 15:53:30 +08:00
caoxiaozhu
34457f9c3e feat: 本体字段治理与风险规则模板执行器重构
- 新增本体字段注册表与字段治理审计脚本
- 重构风险规则模板执行器、DSL 验证与清单分类器
- 完善票据夹服务与差旅请求详情页交互
- 优化趋势图表与总览页数据展示
- 增强报销平台风险分级与模拟公司筛选
- 补充本体字段、风险规则生成与票据夹服务测试覆盖
2026-06-03 15:46:56 +08:00
caoxiaozhu
e12b140508 fix(workbench): show single expense distribution chart 2026-06-03 15:46:51 +08:00
caoxiaozhu
18d716bc6b feat(workbench): show expense distribution as donut chart 2026-06-03 15:31:09 +08:00
caoxiaozhu
74d488adfa fix(workbench): center progress expense type 2026-06-03 15:21:38 +08:00
caoxiaozhu
31052d0b98 feat(workbench): keep progress detail return context 2026-06-03 15:14:44 +08:00
caoxiaozhu
20cb60e247 feat(workbench): add expense stats detail modal 2026-06-03 14:59:55 +08:00
caoxiaozhu
3130c42d76 feat(workbench): separate stale progress items 2026-06-03 12:38:17 +08:00
caoxiaozhu
6fc5e66ea1 feat(workbench): show progress update time first 2026-06-03 12:28:21 +08:00
caoxiaozhu
27dd2f0a0d feat(dashboard): reorganize budget and risk cards 2026-06-03 10:47:11 +08:00
caoxiaozhu
faa39e6c06 test(dashboard): cover shared loading overlay 2026-06-03 09:45:06 +08:00
caoxiaozhu
d060f89d30 style(dashboard): reuse shared loading overlay 2026-06-03 09:43:36 +08:00
caoxiaozhu
0d6327a990 feat(dashboard): polish risk and digital employee boards 2026-06-03 09:41:32 +08:00
caoxiaozhu
15006a05a7 feat: 数字员工财务报告体系与定时提醒及看板快照调度
- 新增数字员工财务报告生成、邮件投递与渲染调度器
- 引入员工画像扫描调度与定时提醒任务
- 完善财务看板快照、排行口径与部门人员占比计算
- 优化数字员工工作看板仪表盘与技能目录
- 增强前端总览页图表、工作台摘要与顶部导航栏交互
- 新增差旅申请规划推动提醒与报销创建会话状态管理
- 补充财务报告、看板调度、数字员工工作记录测试覆盖
2026-06-03 09:25:23 +08:00
caoxiaozhu
0c74b4ab4a feat: 财务看板口径重构与半年模拟数据及报销状态注册表
- 重构 finance_dashboard 口径计算,新增模拟公司画像数据生成与筛选
- 引入 expense_claim_status_registry 统一报销状态流转
- 完善报销草稿流程、Item Sync 与本体解析器
- 优化总览页趋势图、分页组件与请求进度步骤
- 增强报销申请快速预览、本体工具与详情展示
- 新增半年报销模拟数据种子脚本与状态审计工具
- 补充财务看板、报销状态注册与模拟数据测试覆盖
2026-06-02 16:22:59 +08:00
caoxiaozhu
ca691f3ee0 feat: 优化差旅报销预审流程与个人工作台 UI 体系
- 完善 user_agent_application 申请差旅报销预审槽位与消息组装
- 增强预算助理报告与风险建议卡片交互
- 重构登录页视觉样式与移动端响应式适配
- 优化个人工作台、文档中心、政策中心、员工管理等页面布局
- 拆分 travelRequestDetailPreReviewModel 为 advice/submit 模型
- 补充报销草稿、风险复核、Item Sync 与模板执行器测试覆盖
2026-06-02 14:01:51 +08:00
caoxiaozhu
92444e7eae feat: 扩展风险规则体系、审批动态路由与预算中心列表化改造
- 新增 25+ 条风险规则(预算/报销/申请/通用类),完善风险规则模拟与反馈发布机制
- 引入费用审批动态路由、平台风险分级、预审与风险阶段管理
- 预算中心列表化改造,优化票据夹仪表盘与数字员工工作看板
- 新增 Hermes 风险线索收集器、Agent 链路追踪中心
- 扩展数字员工能力库(18 个领域 Skill)与交通费用自动预估
- 完善报销申请快速预览、权限控制与前端测试覆盖
2026-06-01 17:07:14 +08:00
caoxiaozhu
7989f3a159 feat: 新增风险图谱算法与系统仪表盘及操作反馈体系
后端新增风险图谱算法模块、风险观察与反馈服务、规则 DSL
校验器和可解释性引擎,完善系统仪表盘和财务仪表盘统计,
优化 agent 运行和编排执行链路,清理旧开发文档,前端新增
系统趋势、负载热力图等多种仪表盘图表组件,完善操作反馈
对话框和工作台日期选择器,优化报销创建和审批详情交互,
补充单元测试覆盖。
2026-05-30 15:46:51 +08:00
caoxiaozhu
4c59941ec6 feat: 新增票据夹模块并优化 OCR 与员工画像服务
后端新增票据夹端点、数据模型和服务模块,优化 OCR 端点
Schema 和附件操作逻辑,完善员工行为画像服务和辅助函数,
前端新增票据夹视图和服务层,优化文档中心样式和侧边栏导
航,完善员工画像详情弹窗和权限控制,补充单元测试。
2026-05-29 14:51:18 +08:00
caoxiaozhu
678f64d772 feat: 统一后端分页查询与前端服务层适配
后端新增通用分页模块,为报销单、员工、预算、agent 资产等
端点统一接入分页参数和游标查询,优化 repository 层分页实
现,前端服务层适配分页响应结构,完善预算图表和全局样式,
优化侧边栏和企业选择器组件,引入 Element Plus 插件注册。
2026-05-29 14:11:06 +08:00
caoxiaozhu
e080105f9f feat(ui): finalize shared shells and loading states 2026-05-29 13:17:39 +08:00
caoxiaozhu
64cc76c970 refactor(audit): reuse list shells and split models 2026-05-29 10:13:49 +08:00
caoxiaozhu
99e90798d2 refactor(audit): split list detail flows 2026-05-29 09:44:03 +08:00
1193 changed files with 179012 additions and 47967 deletions

View File

@@ -0,0 +1,135 @@
---
name: agent-change-log
description: Use when working in X-Financial after bug fixes, new features, refactors, behavior changes, documentation edits, config edits, concurrent-agent Git commits, or any codebase modification that should leave an incremental human-readable work log.
---
# Agent Change Log
## Overview
This skill keeps a living, incremental work log for X-Financial. After each meaningful modification batch, write down what changed locally, what other agents already committed upstream, what was operated on, what remains uncertain, and what should happen next.
The log should sound like a careful teammate writing for tomorrow's teammate: concrete, warm, and honest.
## When To Use
- After fixing a bug, adding a feature, refactoring, changing behavior, editing documentation, or changing config.
- Before the final response for any turn that changed files.
- Before updating the log in a branch where other agents may have pushed commits.
- After verification, so the entry can include what was actually checked.
- When a failed attempt changed files, generated artifacts, or revealed a risk worth preserving.
Do not use for read-only investigation with no file changes unless the user explicitly asks for a record.
## Log Location
Use one file per day:
```text
document/work-log/YYYY-MM-DD.md
```
If the file does not exist, create it. If it exists, incrementally update it. Never replace the whole file just to add a new entry.
## Required Structure
Each daily file must use these sections in this order:
```markdown
# YYYY-MM-DD 工作日志
## 当日工作内容
## 遗留问题
## TODO
```
Keep this order stable. Add entries under the existing headings instead of creating duplicate headings.
## Required Git Check
Before writing or updating the daily log, manually check Git for upstream and local-ahead commits from other agents.
Run:
```bash
date '+%Y-%m-%d %H:%M:%S %Z'
git fetch --all --prune
git status -sb
git rev-parse --abbrev-ref --symbolic-full-name @{u}
git log --oneline --decorate --max-count=20 HEAD..@{u}
git log --oneline --decorate --max-count=20 @{u}..HEAD
```
Rules:
- Treat `git fetch --all --prune` as the default safe "pull check"; it updates remote refs without merging into a dirty worktree.
- Treat `HEAD..@{u}` as upstream commits not yet in local history.
- Treat `@{u}..HEAD` as local commits not yet in upstream history; these may also come from another agent working in the same checkout.
- If the worktree is clean and the branch is only behind upstream, `git pull --ff-only` may be used to fast-forward before analysis.
- If the worktree is dirty, diverged, or likely to conflict, do not merge/rebase automatically. Record the upstream commits from `HEAD..@{u}` and the blocker in `遗留问题`.
- If there is no upstream branch, record that fact in `遗留问题` and continue with local-only logging.
- When `HEAD..@{u}` has commits, summarize those commits under `当日工作内容` before describing local edits. Mention commit hash, subject, and inferred impact.
- When `@{u}..HEAD` has commits that were not created in the current task, summarize them too, because another local agent may have committed without pushing yet.
- When no upstream or local-ahead commits exist, still record "Git 提交检查:未发现 upstream 新提交或本地 ahead 新提交" in the work entry.
## Entry Rules
1. Get the current local time first:
```bash
date '+%Y-%m-%d %H:%M:%S %Z'
```
2. Run the required Git check and capture whether upstream or local-ahead has new commits.
3. Append a new timestamped bullet under `## 当日工作内容`.
4. Mention Git commits, changed files or modules, the operation, the intent, and the verification result.
5. Add or update `## 遗留问题` whenever there is risk, uncertainty, skipped verification, design debt, Git divergence, or a likely follow-up.
6. Add or update `## TODO` with checkbox items.
7. When a TODO is completed, keep it in place and mark it as:
```markdown
- [x] ~~任务内容~~(完成于 HH:MM证据...
```
## Writing Style
- Write in Simplified Chinese.
- Be specific and a little human: "我把...", "这次先...", "还需要留意..." are good.
- Keep the tone factual. Do not turn the log into a victory lap.
- Prefer concise file names and module names in prose, but include enough context to find the change.
- Work content should be detailed enough that a future agent can continue without asking "你到底改了啥?"
- Leftover issues should include a suggested next step, not only a complaint.
## Work Content Template
```markdown
- HH:MM我完成了 <本次修改目标>。
- Git 提交检查:<git fetch 后 HEAD..upstream 与 upstream..HEAD 的结果;没有就写未发现 upstream 或本地 ahead 新提交>。
- 修改:<文件/模块><做了什么>。
- 操作:<运行了什么命令、迁移了什么状态、重启了什么服务等>。
- 验证:<测试/构建/检查结果;如果没跑,说明原因>。
- 影响:<用户可见变化或工程边界变化>。
```
## Leftover Issue Template
```markdown
- HH:MM<遗留问题或风险>。建议下一步 <具体建议>。
```
## TODO Template
```markdown
- [ ] <下一步动作>来源HH:MM <上下文>
- [x] ~~<已完成动作>~~(完成于 HH:MM证据<命令/文件/结果>
```
## Final Response Checklist
Before saying work is complete:
- Today's `document/work-log/YYYY-MM-DD.md` exists.
- The Git check ran, and upstream plus local-ahead commits from other agents were summarized or explicitly marked as absent.
- `当日工作内容` includes this modification batch.
- `遗留问题` is either updated with real risks or explicitly says no new leftover issue for this batch.
- `TODO` contains new follow-ups and completed items are checked with evidence.
- The final response mentions that the work log was updated.

View File

@@ -0,0 +1,4 @@
interface:
display_name: "Agent Change Log"
short_description: "Record X-Financial changes plus upstream/local commits in the daily work log"
default_prompt: "Use $agent-change-log after a bug fix, feature, refactor, upstream/local commit check, or other file modification to update document/work-log/YYYY-MM-DD.md incrementally."

View File

@@ -0,0 +1,85 @@
---
name: git-checkpoint-commit
description: Use when a coding task finishes a verified bug fix, key feature, risky refactor checkpoint, local backup commit, checkpoint commit, 提交备份, 本地提交, or when an active session has accumulated about five meaningful edit rounds and should create a scoped local git commit without pushing.
---
# Git Checkpoint Commit
## Overview
Use this skill to keep a local git backup loop during active development. The goal is to commit verified, task-scoped progress at meaningful checkpoints without mixing unrelated user changes or pushing remotely.
## Trigger Rules
Create a local checkpoint commit when any condition is true:
- A bug fix is implemented and the targeted regression check passes.
- A key feature slice is implemented and the smallest relevant verification passes.
- A risky refactor reaches a behavior-preserving checkpoint.
- The current session has reached about five meaningful edit rounds since the last commit.
- The user asks for `提交`, `本地提交`, `备份`, `checkpoint`, `commit`, or `形成提交循环`.
Do not use this skill when the user explicitly says not to commit, when the change is exploratory and unverified, or when the only available commit would include unrelated dirty files.
## Workflow
1. Inspect the working tree with `git status --short`.
2. Identify files or hunks owned by the current task.
3. Run the smallest relevant verification first.
- In X-Financial, run backend tests inside `x-financial-main` when backend code is involved.
- Use targeted frontend tests/builds for web-only changes.
4. Commit only the task-owned files.
5. Report the commit hash and verification evidence.
6. Reset the session edit counter to zero after a successful checkpoint.
## Safety Rules
- Never commit unrelated user changes just to make the tree clean.
- Never push as part of this skill.
- Never rewrite history, amend old commits, or run destructive git commands.
- If the same file contains unrelated hunks, split the staging carefully with `git add -p` or a narrower manual patch.
- If the index already contains staged changes, inspect them first; do not mix them into a checkpoint unless they belong to the same current task.
- If verification cannot run, say why in the commit body or final report and prefer a `chore(checkpoint)` message rather than a confident `fix` or `feat`.
## Commit Style
Use normal semantic messages for completed, verified work:
- `fix(workbench): keep application preview after draft save failure`
- `feat(reimbursements): add attachment association job polling`
- `refactor(claims): split draft flow serialization`
Use checkpoint messages for interim backup points:
- `chore(checkpoint): backup attachment association flow`
- `chore(checkpoint): backup after five edit rounds`
Keep the subject concise. Add body lines only when the verification state or scope needs clarity.
## Helper Script
Use `scripts/checkpoint_commit.py` when a path-scoped local commit is enough:
```bash
python3 .codex/skills/git-checkpoint-commit/scripts/checkpoint_commit.py \
--message "chore(checkpoint): backup workbench AI flow" \
web/src/composables/workbenchAiMode/useWorkbenchAiExpenseFlow.js \
web/tests/workbench-ai-mode-switch.test.mjs
```
Preview before committing:
```bash
python3 .codex/skills/git-checkpoint-commit/scripts/checkpoint_commit.py \
--dry-run \
web/src/utils/expenseApplicationPreview.js
```
The script refuses to commit the whole tree unless `--allow-all` is passed. Use `--allow-all` only when the current task truly owns every dirty file.
## Common Mistakes
- Mistaking backup for verification. Verify first, then commit.
- Staging `.` in a dirty worktree. Stage explicit paths or hunks.
- Combining documentation cleanup, feature work, and unrelated local edits in one checkpoint.
- Continuing indefinitely after multiple verified slices. Commit once the counter reaches five meaningful edit rounds.

View File

@@ -0,0 +1,4 @@
interface:
display_name: "Git Checkpoint Commit"
short_description: "Create local backup commits at safe milestones"
default_prompt: "Use $git-checkpoint-commit to checkpoint verified task changes into a local git commit."

View File

@@ -0,0 +1,127 @@
#!/usr/bin/env python3
"""Create a path-scoped local git checkpoint commit."""
from __future__ import annotations
import argparse
import subprocess
import sys
from pathlib import Path
def run_git(args: list[str], cwd: Path, *, check: bool = True) -> subprocess.CompletedProcess[str]:
result = subprocess.run(
["git", *args],
cwd=cwd,
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
timeout=60,
)
if check and result.returncode != 0:
message = result.stderr.strip() or result.stdout.strip()
raise SystemExit(f"git {' '.join(args)} failed: {message}")
return result
def repo_root() -> Path:
result = subprocess.run(
["git", "rev-parse", "--show-toplevel"],
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
timeout=60,
)
if result.returncode != 0:
raise SystemExit("Not inside a git repository.")
return Path(result.stdout.strip())
def load_paths(args: argparse.Namespace) -> list[str]:
paths = list(args.paths)
if args.paths_from_file:
raw_lines = Path(args.paths_from_file).read_text(encoding="utf-8").splitlines()
paths.extend(line.strip() for line in raw_lines if line.strip() and not line.startswith("#"))
return paths
def ensure_clean_index(root: Path) -> None:
staged = run_git(["diff", "--cached", "--name-only"], root).stdout.strip()
if staged:
raise SystemExit(
"Refusing to continue because the index already has staged changes:\n"
f"{staged}\n"
"Commit or unstage them before running this checkpoint helper."
)
def status_for(root: Path, paths: list[str], allow_all: bool) -> str:
command = ["status", "--short"]
if not allow_all:
command.extend(["--", *paths])
return run_git(command, root).stdout.strip()
def infer_message(paths: list[str], allow_all: bool) -> str:
if allow_all or not paths:
return "chore(checkpoint): backup current task changes"
first_parts = [Path(item).parts[0] for item in paths if Path(item).parts]
scope = first_parts[0] if first_parts else "task"
return f"chore(checkpoint): backup {scope} changes"
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("paths", nargs="*", help="Task-owned paths to stage and commit.")
parser.add_argument("-m", "--message", help="Commit message subject/body.")
parser.add_argument("--paths-from-file", help="Read additional pathspecs from a UTF-8 text file.")
parser.add_argument("--dry-run", action="store_true", help="Show matching changes without staging.")
parser.add_argument("--allow-all", action="store_true", help="Allow committing all dirty files.")
parser.add_argument("--no-verify", action="store_true", help="Pass --no-verify to git commit.")
return parser.parse_args()
def main() -> int:
args = parse_args()
root = repo_root()
paths = load_paths(args)
if not paths and not args.allow_all:
raise SystemExit("Pass explicit paths, or use --allow-all when the current task owns all changes.")
current_status = status_for(root, paths, args.allow_all)
if not current_status:
print("No matching changes to commit.")
return 0
print(current_status)
if args.dry_run:
return 0
ensure_clean_index(root)
# 使用 -A 保留删除/重命名等变更,但只作用于明确传入的 pathspec。
if args.allow_all:
run_git(["add", "-A"], root)
else:
run_git(["add", "-A", "--", *paths], root)
staged_summary = run_git(["diff", "--cached", "--name-status"], root).stdout.strip()
if not staged_summary:
raise SystemExit("No staged changes after git add.")
message = args.message or infer_message(paths, args.allow_all)
commit_command = ["commit"]
if args.no_verify:
commit_command.append("--no-verify")
commit_command.extend(["-m", message])
commit_result = run_git(commit_command, root)
sys.stdout.write(commit_result.stdout)
commit_hash = run_git(["rev-parse", "--short", "HEAD"], root).stdout.strip()
print(f"checkpoint_commit={commit_hash}")
return 0
if __name__ == "__main__":
raise SystemExit(main())

51
.env
View File

@@ -1,51 +0,0 @@
APP_NAME=X-Financial
APP_ENV=local
APP_DEBUG=true
API_V1_PREFIX=/api/v1
SETUP_COMPLETED=true
VITE_SETUP_COMPLETED=true
COMPANY_NAME=YGSOFT
COMPANY_CODE=123
ADMIN_EMAIL='admin@admin.com'
VITE_COMPANY_NAME=YGSOFT
VITE_COMPANY_CODE=123
VITE_ADMIN_EMAIL='admin@admin.com'
# Admin login credentials are stored separately under server/.secrets/
WEB_HOST=10.10.10.122
WEB_PORT=5173
VITE_WEB_HOST=10.10.10.122
VITE_WEB_PORT=5173
SERVER_HOST=0.0.0.0
SERVER_PORT=8000
VITE_SERVER_HOST=0.0.0.0
VITE_SERVER_PORT=8000
SERVER_STARTUP_TIMEOUT=300
SERVER_BLOCKING_STARTUP_TIMEOUT=12
VITE_API_BASE_URL=/api/v1
VITE_AUTH_IDLE_TIMEOUT_MINUTES=30
ONLYOFFICE_ENABLED=true
ONLYOFFICE_PUBLIC_URL=http://10.10.10.122:8082
ONLYOFFICE_BACKEND_URL=http://main:8000
ONLYOFFICE_JWT_SECRET=change-me-onlyoffice
HERMES_AGENT_SHARED_TOKEN=change-me-hermes
POSTGRES_HOST=10.10.10.189
POSTGRES_PORT=5432
POSTGRES_DB=postgres
POSTGRES_USER=root
POSTGRES_PASSWORD=8811614287327Leo
VITE_POSTGRES_HOST=10.10.10.189
VITE_POSTGRES_PORT=5432
VITE_POSTGRES_DB=postgres
VITE_POSTGRES_USER=root
DATABASE_URL='postgresql+psycopg://root:8811614287327Leo@10.10.10.189:5432/postgres'
SQLALCHEMY_ECHO=false
REDIS_URL=
VITE_REDIS_URL=
CORS_ORIGINS='["http://10.10.10.122:5173"]'

View File

@@ -31,6 +31,7 @@ ONLYOFFICE_PUBLIC_URL=http://127.0.0.1:8082
ONLYOFFICE_BACKEND_URL=http://127.0.0.1:8000
ONLYOFFICE_JWT_SECRET=change-me-onlyoffice
HERMES_AGENT_SHARED_TOKEN=change-me-hermes
STEWARD_AGENT_RUNTIME=langgraph
POSTGRES_HOST=127.0.0.1
POSTGRES_PORT=5432
@@ -48,4 +49,8 @@ SQLALCHEMY_ECHO=false
REDIS_URL=
VITE_REDIS_URL=
OCR_DEVICE=
OCR_TIMEOUT_SECONDS=180
OCR_MAX_CONCURRENT_WORKERS=1
CORS_ORIGINS='["http://127.0.0.1:5173","http://localhost:5173","http://0.0.0.0:5173"]'

9
.githooks/post-commit Executable file
View File

@@ -0,0 +1,9 @@
#!/bin/sh
# Auto-append a minimal X-Financial agent work-log entry after each commit.
repo_root="$(git rev-parse --show-toplevel 2>/dev/null)" || exit 0
cd "$repo_root" || exit 0
python3 tools/agent-change-log/update_change_log.py \
--event "post-commit hook" \
>/tmp/x-financial-agent-change-log-hook.log 2>&1 || true

24
.gitignore vendored
View File

@@ -7,7 +7,16 @@ web/.vite/
.omc/
.omx/
.claude/
.codex/
*.egg-info/
.codex/*
!.codex/skills/
.codex/skills/*
!.codex/skills/agent-change-log/
!.codex/skills/agent-change-log/**
!.codex/skills/git-checkpoint-commit/
!.codex/skills/git-checkpoint-commit/**
.codex-temp/
.superpowers/
*.log
.DS_Store
Thumbs.db
@@ -16,3 +25,16 @@ __pycache__/
server/.venv/
server/.venv-ocr312
server/.secrets/
server/logs/
server/storage/expense_claims/
server/storage/finance_reports/
server/storage/receipt_folder/
test-results/
.codex-remote-attachments/
tmp-*.png
tmp/
.nezha/
.omo/
.env
.env.local
.env.*.local

View File

@@ -5,6 +5,15 @@
- 所有分析、解释、计划、提交说明和最终回复默认使用简体中文。
- 技术结论要直击重点,必要时给出可验证的文件、命令或测试结果。
## 变更日志 Skill 规范
- 每次修复 bug、新增功能、重构、修改配置或编辑项目文档后必须调用项目级 Skill `agent-change-log`,并增量更新 `document/work-log/YYYY-MM-DD.md`
- 更新日志前必须先执行 Git 拉取检查:默认运行 `git fetch --all --prune``git status -sb``git log HEAD..@{u}``git log @{u}..HEAD`;如果工作区干净且只落后上游,可以 `git pull --ff-only`。发现其他智能体已提交到上游或本地 ahead 提交时,要先把这些提交摘要分析进当天日志。
- 自动化触发由 `tools/agent-change-log/update_change_log.py``.githooks/post-commit` 提供;新 checkout 需要执行 `tools/agent-change-log/install_post_commit_hook.sh` 安装到本地 `.git/hooks/post-commit` 后,提交后才会自动追加最低限度日志。
- 如果当前环境无法写 `.git` 或无法执行 `git fetch`,必须把这个限制写进当天日志;不能把 Skill/AGENTS 规则误当成已经有后台自动化。
- 日志必须保留 `当日工作内容``遗留问题``TODO` 三块TODO 使用 Markdown checkbox完成项勾选并用删除线保留历史。
- 记录要写清楚具体时间、改了什么、操作了什么、验证了什么、还遗留什么问题,以及建议下一步怎么处理。
## 通用代码拆分规范
无论写前端、后端还是算法代码,都必须主动避免“所有方法堆在一个类里 / 一个组件里 / 一个模块里”的写法。遇到类、组件或核心模块持续变大时,优先按职责拆分,而不是继续追加方法和状态。
@@ -32,8 +41,25 @@
- 前端大型 Vue 页面:优先拆分 composable、view model、样式分片、业务工具函数和子组件。
- 算法/规则模块:优先拆分输入解析、规则匹配、评分策略、结果解释和异常处理。
## 验证规范
## 容器与运行环境(必读)
- 后端改动优先在 Docker 容器 `x-financial-main` 中运行验证
- 单元测试设置合理超时,避免长时间卡死。
- 每次重构后至少运行对应服务的定向测试;涉及公共协议时补充端到端或接口测试。
本项目代码是 Docker 容器 `local-x-financial-linux`(镜像 `x-financial-dev:latest`)的源码映射
- **容器映射**:宿主机 `D:\Code\Project\X-Financial` ↔ 容器内 `/app``docker-compose.yml``volumes: - .:/app``working_dir: /app`)。
- **后端 venv**:容器内位于 `/tmp/x-financial-server-venv`(环境变量 `SERVER_VENV_DIR`),不要假设宿主机上有相同的 venv。
- **外部依赖**Qdrant`x-financial-qdrant`、OnlyOffice`x-financial-onlyoffice`)也在同一 compose 网络里。
## 验证规范(硬性约束)
> 本项目代码与运行环境以容器为唯一事实来源。所有后端测试、集成测试、依赖了 Qdrant / OnlyOffice / venv 的验证,都必须在 `local-x-financial-linux` 容器内执行,**不要在宿主机上直接跑 pytest / pip / python**。
- **进入容器跑命令**(最常用):
```bash
docker exec -w /app -e SERVER_VENV_DIR=/tmp/x-financial-server-venv local-x-financial-linux <cmd>
```
- 跑后端测试:`docker exec -w /app -e SERVER_VENV_DIR=/tmp/x-financial-server-venv local-x-financial-linux /tmp/x-financial-server-venv/bin/pytest -q <path>`
- 交互式排查:`docker exec -it -w /app local-x-financial-linux bash`(登录后默认已在 `/app`
- **容器不可用时**(未启动、健康检查失败、镜像丢失):先 `docker compose up -d main` 恢复,再继续验证;不要绕开容器在宿主机另装 venv。
- **单元测试设置合理超时**避免长时间卡死。涉及外部服务Qdrant / OnlyOffice / LLM的测试要么 mock要么确认 compose 网络中依赖服务在线。
- **每次重构后至少运行对应服务的定向测试**;涉及公共协议时补充端到端或接口测试。
- **修改 docker-compose / start.sh / venv 路径相关代码**时,自己也要回容器里跑一次确认改动生效,不要只改文件就声称完成。

View File

@@ -1,45 +1,50 @@
# X-Financial
项目结构已按前后端拆开:
- `web/`:前端工程(当前 Vue + Vite 项目)
- `server/`:后端工程目录
- `docs/`:方案和阶段文档
- `UI/`:界面参考稿
- `document/`:业务文档
根目录统一环境变量:
- `.env`
- `.env.example`
这里集中维护:
- 前端启动端口
- 后端启动端口
- PostgreSQL 连接参数
- `DATABASE_URL`
- `REDIS_URL`
从根目录统一启动:
```bash
./start.sh
```
可选模式:
```bash
./start.sh web
./start.sh server
./start.sh all
```
根目录 `start.sh` 是统一编排入口;前端和后端的子启动脚本分别是 `web/web_start.sh``server/server_start.sh`
手动进入前端目录
```bash
cd web
npm run dev
```
# X-Financial
项目结构已按前后端拆开:
- `web/`:前端工程(当前 Vue + Vite 项目)
- `server/`:后端工程目录
- `docs/`:方案和阶段文档
- `UI/`:界面参考稿
- `document/`:业务文档
根目录统一环境变量:
- `.env`
- `.env.example`
这里集中维护:
- 前端启动端口
- 后端启动端口
- PostgreSQL 连接参数
- `DATABASE_URL`
- `REDIS_URL`
从根目录统一启动:
```bash
./start.sh
```
可选模式:
```bash
./start.sh web
./start.sh server
./start.sh all
```
根目录 `start.sh` 是统一编排入口;前端和后端的子启动脚本分别是 `web/web_start.sh``server/server_start.sh`
Docker Compose 运行方式见 `docker/README.md`
- `docker-compose.yml`只启动主应用容器适合复用已有数据库、ONLYOFFICE 等外部依赖。
- `docker-compose.full.yml`启动主应用、PostgreSQL、Qdrant、ONLYOFFICE 的完整本地开发栈。
手动进入前端目录:
```bash
cd web
npm run dev
```

144
docker-compose.full.yml Normal file
View File

@@ -0,0 +1,144 @@
services:
main:
image: x-financial-dev:latest
container_name: local-x-financial-linux
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
onlyoffice:
condition: service_started
qdrant:
condition: service_started
environment:
WEB_HOST: 0.0.0.0
WEB_PORT: "${WEB_PORT:-5173}"
SERVER_HOST: 0.0.0.0
SERVER_PORT: "${SERVER_PORT:-8000}"
SERVER_RELOAD: "${SERVER_RELOAD:-true}"
SERVER_VENV_DIR: /tmp/x-financial-server-venv
X_FINANCIAL_PREFER_ENV_FILE: "false"
POSTGRES_HOST: postgres
POSTGRES_PORT: "5432"
POSTGRES_DB: "${POSTGRES_DB:-x_financial}"
POSTGRES_USER: "${POSTGRES_USER:-x_financial}"
POSTGRES_PASSWORD: "${POSTGRES_PASSWORD:-x_financial}"
DATABASE_URL: "postgresql+psycopg://${POSTGRES_USER:-x_financial}:${POSTGRES_PASSWORD:-x_financial}@postgres:5432/${POSTGRES_DB:-x_financial}"
ONLYOFFICE_ENABLED: "true"
ONLYOFFICE_PUBLIC_URL: "${LOCAL_ONLYOFFICE_PUBLIC_URL:-http://127.0.0.1:${ONLYOFFICE_PORT:-8082}}"
ONLYOFFICE_BACKEND_URL: "${LOCAL_ONLYOFFICE_BACKEND_URL:-http://main:${SERVER_PORT:-8000}}"
ONLYOFFICE_JWT_SECRET: "${ONLYOFFICE_JWT_SECRET:-x-financial-onlyoffice-dev-secret}"
QDRANT_URL: "http://qdrant:6333"
LIGHTRAG_WORKSPACE: "x_financial_knowledge"
ports:
- "${WEB_PORT:-5173}:${WEB_PORT:-5173}"
- "${SERVER_PORT:-8000}:${SERVER_PORT:-8000}"
- "2223:22"
volumes:
- .:/app
working_dir: /app
command:
- /bin/sh
- -lc
- >
apt-get update &&
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends
python3 python3-pip python3-venv fontconfig openssh-server poppler-data mupdf-tools &&
if ! fc-match 'Noto Sans CJK SC' | grep -qi 'Noto'; then if ! timeout "${CJK_FONT_INSTALL_TIMEOUT_SECONDS:-45}" sh -lc 'DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends fonts-noto-cjk fonts-noto-cjk-extra'; then printf '%s\n' '[WARN] CJK font installation timed out or failed; continuing startup without blocking the app.'; fi; fi &&
printf '%s\n'
'<?xml version="1.0"?>'
'<!DOCTYPE fontconfig SYSTEM "fonts.dtd">'
'<fontconfig>'
' <alias><family>SimSun</family><prefer><family>Noto Serif CJK SC</family></prefer></alias>'
' <alias><family>NSimSun</family><prefer><family>Noto Serif CJK SC</family></prefer></alias>'
' <alias><family>KaiTi</family><prefer><family>Noto Serif CJK SC</family></prefer></alias>'
' <alias><family>FangSong</family><prefer><family>Noto Serif CJK SC</family></prefer></alias>'
' <alias><family>SimHei</family><prefer><family>Noto Sans CJK SC</family></prefer></alias>'
' <alias><family>DengXian</family><prefer><family>Noto Sans CJK SC</family></prefer></alias>'
' <alias><family>Microsoft YaHei</family><prefer><family>Noto Sans CJK SC</family></prefer></alias>'
'</fontconfig>'
> /etc/fonts/local.conf &&
fc-cache -f &&
mkdir -p /run/sshd && /usr/sbin/sshd &&
printf '%s\n' 'cd /app >/dev/null 2>&1 || true' > /etc/profile.d/zz-x-financial-app-dir.sh &&
chmod 644 /etc/profile.d/zz-x-financial-app-dir.sh &&
touch /root/.bashrc /root/.profile &&
if ! grep -qxF 'cd /app >/dev/null 2>&1 || true' /root/.bashrc; then printf '\ncd /app >/dev/null 2>&1 || true\n' >> /root/.bashrc; fi &&
if ! grep -qxF 'cd /app >/dev/null 2>&1 || true' /root/.profile; then printf '\ncd /app >/dev/null 2>&1 || true\n' >> /root/.profile; fi &&
sed -i 's/\r$//' /app/start.sh /app/web/web_start.sh /app/server/server_start.sh &&
chmod +x /app/start.sh /app/web/web_start.sh /app/server/server_start.sh &&
cd /app &&
./start.sh all
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://127.0.0.1:${WEB_PORT:-5173}/ >/dev/null || exit 1"]
interval: 15s
timeout: 5s
retries: 10
start_period: 180s
networks:
- financial-internal
postgres:
image: pgvector/pgvector:pg17
container_name: x-financial-postgres
restart: unless-stopped
environment:
POSTGRES_DB: "${POSTGRES_DB:-x_financial}"
POSTGRES_USER: "${POSTGRES_USER:-x_financial}"
POSTGRES_PASSWORD: "${POSTGRES_PASSWORD:-x_financial}"
ports:
- "${POSTGRES_HOST_PORT:-55432}:5432"
volumes:
- postgres-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U \"$${POSTGRES_USER}\" -d \"$${POSTGRES_DB}\""]
interval: 15s
timeout: 5s
retries: 10
start_period: 30s
networks:
- financial-internal
qdrant:
image: qdrant/qdrant:latest
container_name: x-financial-qdrant
restart: unless-stopped
ports:
- "${QDRANT_HTTP_PORT:-6333}:6333"
- "${QDRANT_GRPC_PORT:-6334}:6334"
volumes:
- qdrant-storage:/qdrant/storage
healthcheck:
test: ["CMD-SHELL", "bash -lc 'exec 3<>/dev/tcp/127.0.0.1/6333' || exit 1"]
interval: 15s
timeout: 5s
retries: 10
start_period: 30s
networks:
- financial-internal
onlyoffice:
image: onlyoffice/documentserver:latest
container_name: x-financial-onlyoffice
restart: unless-stopped
environment:
JWT_ENABLED: "true"
JWT_SECRET: "${ONLYOFFICE_JWT_SECRET:-x-financial-onlyoffice-dev-secret}"
ports:
- "${ONLYOFFICE_PORT:-8082}:80"
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://127.0.0.1/healthcheck >/dev/null || exit 1"]
interval: 15s
timeout: 5s
retries: 10
start_period: 60s
networks:
- financial-internal
networks:
financial-internal:
name: financial-internal
volumes:
postgres-data:
qdrant-storage:

8
docker-compose.gpu.yml Normal file
View File

@@ -0,0 +1,8 @@
services:
main:
gpus: all
shm_size: "8gb"
environment:
NVIDIA_VISIBLE_DEVICES: all
NVIDIA_DRIVER_CAPABILITIES: compute,utility
OCR_DEVICE: "${OCR_DEVICE:-gpu:0}"

View File

@@ -0,0 +1,36 @@
services:
main:
depends_on:
postgres:
condition: service_healthy
environment:
POSTGRES_HOST: postgres
POSTGRES_PORT: "5432"
POSTGRES_DB: "${POSTGRES_DB:-x_financial}"
POSTGRES_USER: "${POSTGRES_USER:-x_financial}"
POSTGRES_PASSWORD: "${POSTGRES_PASSWORD:-x_financial}"
DATABASE_URL: "postgresql+psycopg://${POSTGRES_USER:-x_financial}:${POSTGRES_PASSWORD:-x_financial}@postgres:5432/${POSTGRES_DB:-x_financial}"
postgres:
image: pgvector/pgvector:pg17
container_name: x-financial-postgres
restart: unless-stopped
environment:
POSTGRES_DB: "${POSTGRES_DB:-x_financial}"
POSTGRES_USER: "${POSTGRES_USER:-x_financial}"
POSTGRES_PASSWORD: "${POSTGRES_PASSWORD:-x_financial}"
ports:
- "${POSTGRES_HOST_PORT:-55432}:5432"
volumes:
- postgres-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U \"$${POSTGRES_USER}\" -d \"$${POSTGRES_DB}\""]
interval: 15s
timeout: 5s
retries: 10
start_period: 30s
networks:
- financial-internal
volumes:
postgres-data:

View File

@@ -1,38 +1,37 @@
services:
main:
image: x-financial-dev:latest
container_name: x-financial-main
restart: unless-stopped
depends_on:
onlyoffice:
condition: service_started
qdrant:
condition: service_started
environment:
WEB_HOST: 0.0.0.0
SERVER_HOST: 0.0.0.0
SERVER_VENV_DIR: /tmp/x-financial-server-venv
X_FINANCIAL_PREFER_ENV_FILE: "true"
ONLYOFFICE_ENABLED: "${ONLYOFFICE_ENABLED:-true}"
ONLYOFFICE_PUBLIC_URL: "${ONLYOFFICE_PUBLIC_URL:-http://127.0.0.1:${ONLYOFFICE_PORT:-8082}}"
ONLYOFFICE_BACKEND_URL: "http://main:${SERVER_PORT:-8000}"
ONLYOFFICE_JWT_SECRET: "${ONLYOFFICE_JWT_SECRET:-x-financial-onlyoffice-dev-secret}"
QDRANT_URL: "http://qdrant:6333"
LIGHTRAG_WORKSPACE: "x_financial_knowledge"
ports:
- "${WEB_PORT:-5173}:${WEB_PORT:-5173}"
- "${SERVER_PORT:-8000}:${SERVER_PORT:-8000}"
- "2223:22"
volumes:
- .:/app
working_dir: /app
command:
- /bin/sh
- -lc
- >
services:
main:
image: x-financial-dev:latest
container_name: local-x-financial-linux
restart: unless-stopped
environment:
WEB_HOST: 0.0.0.0
WEB_PORT: "${WEB_PORT:-5173}"
SERVER_HOST: 0.0.0.0
SERVER_PORT: "${SERVER_PORT:-8000}"
SERVER_RELOAD: "${SERVER_RELOAD:-true}"
SERVER_VENV_DIR: /tmp/x-financial-server-venv
X_FINANCIAL_PREFER_ENV_FILE: "true"
ONLYOFFICE_ENABLED: "${ONLYOFFICE_ENABLED:-false}"
ONLYOFFICE_PUBLIC_URL: "${ONLYOFFICE_PUBLIC_URL:-}"
ONLYOFFICE_BACKEND_URL: "${ONLYOFFICE_BACKEND_URL:-}"
ONLYOFFICE_JWT_SECRET: "${ONLYOFFICE_JWT_SECRET:-x-financial-onlyoffice-dev-secret}"
QDRANT_URL: "${QDRANT_URL:-}"
LIGHTRAG_WORKSPACE: "x_financial_knowledge"
ports:
- "${WEB_PORT:-5173}:${WEB_PORT:-5173}"
- "${SERVER_PORT:-8000}:${SERVER_PORT:-8000}"
- "2223:22"
volumes:
- .:/app
working_dir: /app
command:
- /bin/sh
- -lc
- >
apt-get update &&
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends
python3 python3-pip python3-venv fontconfig fonts-noto-cjk fonts-noto-cjk-extra &&
python3 python3-pip python3-venv fontconfig openssh-server poppler-data mupdf-tools &&
if ! fc-match 'Noto Sans CJK SC' | grep -qi 'Noto'; then if ! timeout "${CJK_FONT_INSTALL_TIMEOUT_SECONDS:-45}" sh -lc 'DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends fonts-noto-cjk fonts-noto-cjk-extra'; then printf '%s\n' '[WARN] CJK font installation timed out or failed; continuing startup without blocking the app.'; fi; fi &&
printf '%s\n'
'<?xml version="1.0"?>'
'<!DOCTYPE fontconfig SYSTEM "fonts.dtd">'
@@ -48,63 +47,24 @@ services:
> /etc/fonts/local.conf &&
fc-cache -f &&
mkdir -p /run/sshd && /usr/sbin/sshd &&
printf '%s\n' 'cd /app >/dev/null 2>&1 || true' > /etc/profile.d/zz-x-financial-app-dir.sh &&
chmod 644 /etc/profile.d/zz-x-financial-app-dir.sh &&
touch /root/.bashrc /root/.profile &&
if ! grep -qxF 'cd /app >/dev/null 2>&1 || true' /root/.bashrc; then printf '\ncd /app >/dev/null 2>&1 || true\n' >> /root/.bashrc; fi &&
if ! grep -qxF 'cd /app >/dev/null 2>&1 || true' /root/.profile; then printf '\ncd /app >/dev/null 2>&1 || true\n' >> /root/.profile; fi &&
sed -i 's/\r$//' /app/start.sh /app/web/web_start.sh /app/server/server_start.sh &&
chmod +x /app/start.sh /app/web/web_start.sh /app/server/server_start.sh &&
cd /app &&
./start.sh all
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://127.0.0.1:${WEB_PORT:-5173}/ >/dev/null || exit 1"]
interval: 15s
timeout: 5s
retries: 10
start_period: 180s
networks:
- financial-internal
qdrant:
image: qdrant/qdrant:latest
container_name: x-financial-qdrant
restart: unless-stopped
ports:
- "${QDRANT_HTTP_PORT:-6333}:6333"
- "${QDRANT_GRPC_PORT:-6334}:6334"
volumes:
- qdrant-storage:/qdrant/storage
healthcheck:
test: ["CMD-SHELL", "bash -lc 'exec 3<>/dev/tcp/127.0.0.1/6333' || exit 1"]
interval: 15s
timeout: 5s
retries: 10
start_period: 30s
networks:
- financial-internal
onlyoffice:
image: onlyoffice/documentserver:latest
container_name: x-financial-onlyoffice
restart: unless-stopped
environment:
JWT_ENABLED: "true"
JWT_SECRET: "${ONLYOFFICE_JWT_SECRET:-x-financial-onlyoffice-dev-secret}"
ports:
- "${ONLYOFFICE_PORT:-8082}:80"
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://127.0.0.1/healthcheck >/dev/null || exit 1"]
interval: 15s
timeout: 5s
retries: 10
start_period: 60s
networks:
- financial-internal
networks:
financial-internal:
name: financial-internal
volumes:
qdrant-storage:
printf '%s\n' 'cd /app >/dev/null 2>&1 || true' > /etc/profile.d/zz-x-financial-app-dir.sh &&
chmod 644 /etc/profile.d/zz-x-financial-app-dir.sh &&
touch /root/.bashrc /root/.profile &&
if ! grep -qxF 'cd /app >/dev/null 2>&1 || true' /root/.bashrc; then printf '\ncd /app >/dev/null 2>&1 || true\n' >> /root/.bashrc; fi &&
if ! grep -qxF 'cd /app >/dev/null 2>&1 || true' /root/.profile; then printf '\ncd /app >/dev/null 2>&1 || true\n' >> /root/.profile; fi &&
sed -i 's/\r$//' /app/start.sh /app/web/web_start.sh /app/server/server_start.sh &&
chmod +x /app/start.sh /app/web/web_start.sh /app/server/server_start.sh &&
cd /app &&
./start.sh all
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://127.0.0.1:${WEB_PORT:-5173}/ >/dev/null || exit 1"]
interval: 15s
timeout: 5s
retries: 10
start_period: 180s
networks:
- financial-internal
networks:
financial-internal:
name: financial-internal

View File

@@ -1,67 +1,127 @@
# Docker Compose
This project currently uses the Vite `__setup/*` middleware during the initial setup flow.
Because of that, the Docker deployment keeps the web frontend and FastAPI startup chain in
the same main container and runs the existing root `start.sh`.
## Start
```bash
cp .env.example .env
docker compose up -d
```
Open:
```text
http://<your-linux-host>:5173
```
## Container Layout
- `main`: web + FastAPI main container
- `onlyoffice`: ONLYOFFICE Document Server
- `postgres`: PostgreSQL database container
The project root is mounted directly into the main container:
```text
.:/app
```
That means the container reads your existing `.env`, source code, `server/.secrets`, logs,
and generated dependency directories directly from the mapped project folder.
This is a `compose`-only setup. There is no custom `Dockerfile`.
The tradeoff is that the `main` container installs the Python runtime packages it needs
when it starts.
## Persistence
The PostgreSQL data directory is stored in the named volume `postgres_data`.
## Notes
- Most configuration should be maintained in the project root `.env`.
- The first `docker compose up -d` does not require an existing `.env`; the compose file
uses built-in defaults for the PostgreSQL container and the main container database URL.
- Docker Compose only overrides a few values that must differ inside containers:
- `WEB_HOST=0.0.0.0`
- `SERVER_HOST=0.0.0.0`
- `POSTGRES_HOST=postgres`
- `POSTGRES_PORT=5432`
- `DATABASE_URL=...@postgres:...`
- PostgreSQL is also published to the host by default as `127.0.0.1:55432`.
- ONLYOFFICE is published to the host by default as `127.0.0.1:8082`.
- First boot with `SETUP_COMPLETED=false` starts the setup UI only.
- After you complete setup in the browser, the Vite setup bridge will start FastAPI in the
same container using the saved runtime configuration.
- On later restarts, `start.sh` will detect the saved setup state and start both web and
server automatically.
- If you access the system from another machine, make sure `CORS_ORIGINS` in `.env` includes
the frontend address you actually use.
- For Navicat or any host-side client, use `127.0.0.1:55432`.
- If you need to access ONLYOFFICE from another machine, override `ONLYOFFICE_PUBLIC_URL`
so the browser can reach the document server address you actually expose.
- For the setup page, using `127.0.0.1` is acceptable in this Docker layout; the internal
test bridge will resolve that back to the Docker PostgreSQL service.
# Docker Compose
X-Financial 现在按运行依赖分成两层 Docker Compose
- `docker-compose.yml`:只启动主应用容器,适合已经有远端 PostgreSQL、ONLYOFFICE 或 Qdrant 的环境。
- `docker-compose.full.yml`:启动完整本地开发栈,适合没有外部依赖、希望本机一次性跑齐所有服务的环境。
主应用容器仍然同时启动 Web 前端和 FastAPI 后端,并复用根目录 `start.sh`
项目根目录会挂载到容器内 `/app`
## 轻量启动:只跑主应用
适合你已经有数据库和 ONLYOFFICE 的情况。
```bash
cp .env.example .env
docker compose up -d
```
默认只会启动:
```text
main
```
打开:
```text
http://<your-linux-host>:5273
```
这条路径不会主动拉起本地 PostgreSQL、Qdrant 或 ONLYOFFICE。
数据库、ONLYOFFICE 和 Qdrant 地址都从 `.env` 或外部环境变量读取。
常见外部依赖变量:
```text
DATABASE_URL
POSTGRES_HOST
POSTGRES_PORT
ONLYOFFICE_ENABLED
ONLYOFFICE_PUBLIC_URL
ONLYOFFICE_BACKEND_URL
QDRANT_URL
```
## 完整启动:本地全栈
适合没有远端数据库和 ONLYOFFICE 的情况。
```bash
docker compose -f docker-compose.full.yml up -d
```
会启动:
```text
main
postgres
qdrant
onlyoffice
```
本地服务端口:
```text
Web: 5273
FastAPI: 8000
PostgreSQL: 55432 -> 5432
Qdrant: 6333 / 6334
ONLYOFFICE: 8082
SSH: 2223
```
完整栈会把主容器内的数据库地址指向 `postgres:5432`
并把 Qdrant 地址指向 `http://qdrant:6333`
ONLYOFFICE 默认使用本机可访问地址:
```text
http://127.0.0.1:8082
```
如果浏览器从另一台机器访问,需要覆盖:
```bash
LOCAL_ONLYOFFICE_PUBLIC_URL=http://<host>:8082 \
docker compose -f docker-compose.full.yml up -d
```
如果 ONLYOFFICE 回调后端也需要外部地址,可以同时覆盖:
```bash
LOCAL_ONLYOFFICE_BACKEND_URL=http://<host>:8000 \
docker compose -f docker-compose.full.yml up -d
```
## 可选:只额外启动本地 PostgreSQL
如果只想在轻量主容器旁边补一个本地 PostgreSQL可以使用覆盖文件
```bash
docker compose -f docker-compose.yml -f docker-compose.postgres.yml up -d
```
这会启动:
```text
main
postgres
```
## 停止与清理
停止当前默认轻量栈:
```bash
docker compose down
```
停止完整本地栈:
```bash
docker compose -f docker-compose.full.yml down
```
如需删除本地数据卷,先确认不再需要其中数据,再手动执行带 `-v` 的清理命令。

View File

@@ -0,0 +1,32 @@
# 附件自动关联后台任务实施计划
## 目标
把小财管家 AI 模式里的附件关联从前端会话内存任务改为后端可查询后台任务,保证用户退出或刷新当前会话后,附件关联仍能继续完成并可恢复状态。
## 执行清单
- [x] 定位当前断链根因:前端依赖 `File` 对象和内存 `Map`
- [x] 确认票据夹已有 `receipt_id`、源文件和关联状态能力。
- [x] 落开发方案文档。
- [x] 实现后端任务 schema 和内存任务池。
- [x] 实现后端任务 API。
- [x] 实现后端票据夹源文件归集到报销单明细。
- [x] 增加后端测试。
- [x] 实现前端任务创建、轮询和恢复。
- [x] 增加前端测试断言。
- [x] 执行容器后端定向测试。
- [x] 执行前端定向测试和构建。
## 验证结果
- 后端定向测试:`6 passed`
- 前端定向测试:`12 passed`
- 前端构建:通过,保留既有 chunk size warning。
- 运行时检查:新任务查询路由已加载,未知任务返回“附件关联任务不存在或已失效。”
## 关键决策
- 第一版使用后端内存任务池和 FastAPI `BackgroundTasks`,解决前端会话断链。
- 第一版不新增数据库任务表,服务重启后的任务恢复作为后续增强。
- 前端消息只保存 `job_id`、状态和票据引用,不再保存附件原件。

View File

@@ -0,0 +1,146 @@
# AI 意图规划器
## 功能一句话
把用户一句自然语言先交给大模型识别成“动作和步骤”的结构化计划,再由前端/后端确定性执行器逐步校验和执行;规则只作为模型不可用或结构非法时的兜底。
## 背景
用户真实表达往往不是一个简单关键词,而是一个目标:
```text
去上海出差,辅助国网仿生产服务器部署,交通火车,直接提交
```
这句话包含至少四层语义:
- 业务对象:差旅费用申请。
- 已给字段:地点、事由、交通方式。
- 用户动作:直接提交,不只是生成草稿。
- 执行步骤:生成申请核对表、校验必填字段、查重、提交审批。
如果继续用前端规则直接判断,会越来越像关键词路由;正确方向是让大模型先拆成结构化计划,系统只执行经过白名单校验的步骤。
## 目标
- 大模型作为复杂意图的主识别器,输出结构化 `intent plan`
- `intent plan` 明确描述用户要执行的动作、业务字段、缺失字段和步骤列表。
- 执行器只认计划中的白名单步骤,不直接相信模型文本。
- 字段齐全且用户明确“直接提交”时,系统自动走完整链路。
- 字段缺失、风险阻断、重复申请或低置信度时,系统停在核对表或风险提示。
- 本地规则只作为 `rule_fallback`,不得伪装成模型判断。
## 非目标
- 不让大模型直接写数据库、提交审批或绑定附件。
- 不引入 LangChain 高层 Agent 来替代现有业务服务。
- 不让 LangGraph 直接接管模型供应商密钥、数据库写入或审批副作用。
- 不绕过已有申请预览、规则测算、重复申请核查和提交接口。
- 不把所有财务场景一次性改完;第一阶段先覆盖个人工作台 AI 模式里的差旅申请链路。
## 结构化计划契约
前端执行器消费统一结构:
```json
{
"source": "llm_function_call",
"intent": "create_travel_application",
"requestedAction": "submit",
"confidence": 0.91,
"sourceText": "去上海出差,辅助国网仿生产服务器部署,交通火车,直接提交",
"slots": {
"location": "上海",
"reason": "辅助国网仿生产服务器部署",
"transportMode": "火车"
},
"missingFields": [],
"steps": [
"build_application_preview",
"validate_required_fields",
"run_duplicate_precheck",
"submit_application"
]
}
```
## 步骤白名单
- `build_application_preview`:生成申请核对表,复用现有申请预览能力。
- `validate_required_fields`:用确定性代码校验必填字段和字段格式。
- `run_duplicate_precheck`:提交前查询同日期或重叠申请单。
- `submit_application`:调用现有申请提交动作;只有用户明确要求提交且前置校验通过才执行。
- `save_application_draft`:调用现有申请草稿保存能力。
- `create_reimbursement_draft`:调用现有报销草稿创建能力。
- `associate_attachments`:调用现有附件关联 runner缺少 `receipt_ids` 或匹配不唯一时阻断,不能假成功。
- `link_existing_application`:调用现有报销草稿创建链路并写入申请关联 flag申请单不存在、未审批或已被报销时阻断。
## 数据流
```text
用户输入
steward LLM function calling
模型计划归一化与白名单校验
可执行 intent plan
申请/报销/附件等确定性执行器
核对表、风险提示、草稿或提交结果
```
当模型不可用、超时或返回不可执行结构时:
```text
模型失败
本地 rule_fallback 生成保守计划
同一个执行器继续处理
```
## 安全边界
- 模型只负责“理解”和“拆步骤”,不拥有副作用权限。
- 执行器必须校验 `intent``steps` 是否在白名单内;未知 action 必须阻断,不能调用业务服务。
- 提交前必须走 `readyToSubmit` 和重复申请 precheck。
- 提交类副作用必须带用户确认和 precheck 通过证据。
- 地点、日期、事由等字段仍由现有申请预览和规则校验模块判断。
- 模型置信度低、流程冲突或必填字段缺失时,不自动提交。
## 第一阶段落地
- 新增前端 planner model把后端 `StewardPlanResponse` 映射成前端 `intent plan`
- 个人工作台 AI 模式在命中差旅申请候选时,优先调用现有 `/steward/plans` 获取模型计划。
- 模型计划可执行时,按 `steps` 生成申请核对表并在条件满足时自动提交。
- 模型不可用或计划不可执行时,使用本地 `rule_fallback` 保持体验不倒退。
- 保留既有普通小财管家路径,用来处理无法直接执行或更复杂的多任务场景。
## LangGraph 迁移方向
后端小财管家的规划入口、槽位决策入口和运行时动作决策入口已经开始迁入 LangGraph。
后续不再继续把感知、规划、补字段、运行时动作判断堆进自研 `if/else` 编排,而是按 node 拆分:
- `model_intent_node`:模型 function calling 规划。
- `slot_tool_decision_node`:字段缺口与追问判断,失败时进入规则兜底。
- `runtime_memory_context_node`:合并前端运行时状态和持久化 `steward_state`
- `runtime_tool_decision_node`:用户补充、确认、取消、继续执行等运行时判断。
- `runtime_action_decision_node`:已选流程确认等不需要模型的确定性行动路由。
- `action_plan_node`:生成白名单 `StewardActionStep`,当前已覆盖申请预览、保存草稿、直接提交和报销草稿。
- `human_review_node`:保存草稿、提交审批、关联申请单前的确认点。
- `action_execute_node`:调用现有确定性业务服务;当前已由 `/steward/actions/execute``StewardGraphActionRuntime``StewardActionExecutor` 提供 checkpoint、pending interrupt 和幂等重放。
- `persist_state_node`:合并 conversation state 和 steward state。
当前 `plans` 已返回服务端 `action_steps``slot-decisions` / `runtime-decisions` 已默认走 `StewardGraphRuntime`
如果 LangGraph 图节点异常,服务端会退回原有 Agent 和规则兜底,避免框架层故障影响用户会话。
详细迁移计划见 `LANGGRAPH_RUNTIME_MIGRATION.md`
## 测试策略
- planner model 单元测试模型计划归一化、rule fallback、政策咨询排除。
- 前端静态接线测试:主流程必须先请求 steward plan再 fallback。
- 申请预览回归测试:`直接提交` 不得污染事由;缺日期不得伪造字段。
- 构建验证:`npm --prefix web run build`

View File

@@ -0,0 +1,420 @@
# 小财管家 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 2slot/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 3action 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 4checkpoint 与 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 行先拆文件。

View File

@@ -0,0 +1,32 @@
# AI 意图规划器 TODO
## 第一阶段
- [x] 落地 AI 意图规划器概念文档,明确大模型负责拆计划、业务代码负责执行。
- [x] 新增前端 planner model统一模型计划和本地 fallback 的输出结构。
- [x] 个人工作台 AI 模式先请求 steward 模型计划,再使用本地 fallback。
- [x] 差旅申请直提链路改为消费 `intent plan.steps`,不再直接消费正则识别结果。
- [x] 补齐 planner model 与主流程接线回归测试。
- [x] 跑前端构建和定向测试。
- [x] 后端 `/steward/plans` 增加 `requested_action` 输出,减少前端从原句推断“提交/保存”的比例。
- [x] 引入 LangGraph并默认用 `StewardGraphPlannerService` 接管 `/steward/plans` 规划编排。
- [x] 落地 LangGraph runtime 迁移计划文档:`LANGGRAPH_RUNTIME_MIGRATION.md`
- [x] 新增 `StewardGraphRuntime`,接管 `slot-decisions``runtime-decisions` 的 LangGraph 路由。
- [x] 为 LangGraph runtime 增加图内规则兜底和端点级 legacy Agent 兜底。
- [x]`/steward/plans` 增加服务端白名单 `action_steps`,覆盖申请、报销、保存草稿和直接提交的基础动作规划。
- [x] 前端 planner model 优先消费服务端 `task.action_steps`,旧响应才回退本地步骤推导。
- [x] 新增 `/steward/actions/execute``StewardActionExecutor`,把未知 action 拒绝、提交确认门禁、precheck 阻断、申请草稿保存、申请提交和报销草稿创建接到现有业务服务。
- [x] 前端新增 `executeStewardAction()` 服务方法,并让 steward suggested action 携带服务端可执行 action step。
- [x] AI 工作台点击可执行 steward action 时调用 `/steward/actions/execute`;申请直接提交会先跑 `run_duplicate_precheck`,通过后再提交。
- [x] `complete_with_tool_call()` 增加 main 失败后 backup tool-call 成功路径测试,保证模型成功路径能从 backup 返回 `llm_function_call`
- [x] 新增 `StewardGraphActionRuntime`,把 action executor 包成 LangGraph `action_execute_node`,并用 `conversation_id + client_trace_id``AgentConversation.state_json` 中持久化 checkpoint。
- [x] 对提交确认生成 pending interrupt重复 client trace 直接重放 checkpoint避免重复保存草稿或重复提交。
- [x] `link_existing_application` 接入现有报销草稿创建链路并写入申请关联 flag。
- [x] `associate_attachments` 接入现有附件关联 runner按 receipt_ids 归集到可匹配报销草稿。
## 后续阶段
- [ ] 用真实 MiniMax / backup 配置再回放 `/steward/plans`,确认真实环境返回 `planning_source=llm_function_call`,不是规则兜底。
- [ ] 将当前 `AgentConversation.state_json` checkpoint 抽象为可替换的 durable checkpointer并补恢复/清理策略。
- [ ] 为每个 LangGraph node 写入可追溯 trace展示模型调用、规则降级、等待确认和动作执行结果。
- [ ] 在 LangGraph 路径覆盖申请/报销核心链路后,再逐步删除旧 `StewardPlannerService` 的重复编排。

View File

@@ -0,0 +1,132 @@
# Agent链路追踪中心 概念文档
## 功能一句话
为 Orchestrator 全链路运行提供统一 trace 采集、查询和前端回放入口,让管理员能按 `run_id``conversation_id` 还原一次 Agent 对话从意图识别到最终回复的全过程。
## 背景与问题
- 当前现状:系统已有 `agent_runs``agent_tool_calls``semantic_parse_logs` 和对话消息,但它们分散在运行记录、工具调用、语义解析与系统日志中。
- 用户痛点:线上 Agent 回答异常时,只能看局部日志或 Hermes 工作记录,难以判断问题出在意图路由、知识检索、规则引擎、数字员工任务还是回复生成。
- 业务影响Agent 链路越长,排障成本越高;没有可重放视图会影响交付、演示和运维可信度。
## 目标与非目标
### 目标
- [G1] 后端沉淀统一的 Agent trace 事件模型,按运行顺序记录关键阶段输入、输出、状态、耗时和错误。
- [G2] 提供 trace 查询接口,支持按 `run_id` 查看单次运行,按 `conversation_id` 查看多轮会话链路。
- [G3] 前端新增 Agent Trace Center 入口,展示运行时间线、工具调用、语义解析、路由上下文和最终回复。
- [G4] 保留现有 Agent Run / ToolCall 数据结构,避免破坏数字员工工作记录和系统日志页面。
### 非目标
- [NG1] 本轮不做重新执行真实业务动作的“调试重跑”,只做历史重放。
- [NG2] 本轮不接入 OpenTelemetry、Jaeger 等外部分布式追踪系统。
- [NG3] 本轮不改造总账、预算、报销审批等业务语义。
- [NG4] 本轮不做跨服务链路采样策略和海量归档策略。
## 用户与场景
- 目标用户系统管理员、财务系统运维、Agent 能力开发者、实施顾问。
- 使用入口:系统日志详情、数字员工工作记录、报销助手消息中的 `run_id`、新增 Trace Center 页面。
- 核心场景:
- 管理员打开某次异常回复,查看每一步输入输出和耗时。
- 实施人员按会话查看多轮上下文,判断上下文是否被错误继承。
- 开发者定位工具调用失败、语义识别降级或路由选错 Agent 的原因。
- 异常场景:
- 运行失败但没有工具调用时,仍展示已记录的 orchestration 阶段。
- 旧数据没有 trace event 时,接口回退展示 `agent_runs``semantic_parse``tool_calls`
## 功能能力
- [C1] 输入能力:接收 `run_id``conversation_id`、Agent、状态、来源、关键字等查询条件。
- [C2] 采集能力:记录 `received``context_hydrated``semantic_parsed``agent_selected``capability_selected``tool_invoked``response_built``conversation_updated``failed` 等事件。
- [C3] 输出能力:返回 trace 摘要、事件时间线、工具调用、语义解析、路由 JSON、最终回复和关联会话消息。
- [C4] 状态与权限:复用现有登录与页面权限,管理员/可访问设置页用户可查看全量 trace。
- [C5] 边界与降级:旧运行没有 trace events 时,按现有 run/tool/semantic 数据合成最小时间线。
## 方案设计
### 前端
- 页面/组件:
- 新增 `AgentTraceCenterView` 或设置页内 Trace Center 分区。
- 新增 trace 详情组件,复用现有日志详情的直角企业级视觉。
- 从日志详情、数字员工工作记录、报销助手操作反馈中可跳转到 trace 详情。
- 交互状态:
- 列表支持关键字、状态、Agent、来源筛选。
- 详情展示左侧时间线、右侧输入输出 JSON、顶部摘要。
- 支持加载、空态、错误态和刷新。
- 展示规则:
- 事件按 `started_at``sequence` 升序展示。
- 失败事件突出错误信息。
- 大 JSON 使用可滚动代码块,避免撑破页面。
### 后端
- 接口/服务:
- `GET /api/v1/agent-traces`:查询 trace 列表。
- `GET /api/v1/agent-traces/{run_id}`:读取单次运行 trace。
- `GET /api/v1/agent-traces/conversations/{conversation_id}`:读取会话 trace。
- 权限与校验:
- 复用当前 API 依赖和系统登录态。
- 不允许通过 trace 接口修改业务数据。
- 持久化:
- 新增 `agent_trace_events` 表。
- 通过 `AgentTraceService` 封装记录、查询、合成旧数据时间线。
### 算法与规则
- 规则输入Agent 运行阶段、工具调用结果、语义解析结果和会话消息。
- 规则流程:
- 采集阶段按固定事件名记录。
- 查询阶段按事件序列合并 run、semantic、tool、conversation。
- 无事件时从历史 run 数据合成 fallback timeline。
- 结果解释:
- 每个事件输出 `title``summary``status``duration_ms``input_json``output_json``error_message`
## 算法与公式
当前功能不涉及评分、预算或风控公式,只涉及耗时统计:
$$
duration\_ms = finished\_at - started\_at
$$
变量说明:
- $duration\_ms$:阶段耗时,单位毫秒。
- $finished\_at$:阶段结束时间。
- $started\_at$:阶段开始时间。
## 测试方案
- 单元测试:覆盖 `AgentTraceService` 记录事件、查询详情、旧 run fallback 时间线。
- 接口测试:覆盖 trace 列表、单 run 详情、会话详情。
- 前端交互测试:覆盖 trace 数据归一化、状态文案、空态和错误态。
- 端到端测试:通过一次 Orchestrator 用户消息生成 `run_id`,验证详情接口能返回语义解析、路由和至少一个事件。
- 回归测试:确认原 `agent-runs` 接口、数字员工工作记录、系统日志详情不破坏。
- 手工验证:在浏览器打开 Trace Center检查列表、详情和 JSON 展示。
## 指标与验收
- [A1] 功能验收:一次 Orchestrator 调用后,能通过 `run_id` 查询到完整 trace 详情。
- [A2] 性能指标:单次 trace 详情查询在常规数据量下不引入明显慢查询;默认列表限制数量。
- [A3] 质量指标:后端定向测试在 Docker `x-financial-main` 容器内 60s 超时内通过。
- [A4] 安全/权限指标trace 接口只读,不触发业务动作或副作用。
- [A5] 可观测性:失败运行也能看到最后成功事件和失败事件。
## 风险与开放问题
- 风险:当前工作树已有大量未提交改动,本轮实现必须避免覆盖既有业务改动。
- 已处理依赖:新增 trace 模型已纳入 `Base` 导入,`AgentTraceService.ensure_storage_ready()` 会按需创建 trace 事件表。
- 待确认:后续是否需要接 OpenTelemetry、跨容器 trace 或长期归档策略。
- 降级策略:没有 trace event 的旧 run 通过 `semantic_parse``tool_calls``route_json` 合成只读时间线。
## 本轮实现记录
- 后端已完成 `AgentTraceEvent``AgentTraceService``/api/v1/agent-traces` 只读接口。
- Orchestrator 已在接收请求、会话补全、语义识别、路由、工具调用、会话写回、最终回复和失败路径写入 trace event。
- 前端已在系统设置中新增 Agent Trace Center并从日志详情、数字员工工作记录跳转到指定 `run_id`
- 本轮保持非目标不变:不做真实业务重跑、不接 OpenTelemetry、不处理 GL/总账体系和前端统一状态管理。

View File

@@ -0,0 +1,55 @@
# Agent链路追踪中心 开发 TODO
## 使用规则
- 每个 TODO 必须对应 `CONCEPT.md` 中的目标、能力或验收点。
- 只有完成并验证后,才能把 `[ ]` 改成 `[x]`
- 勾选时在任务后补充简短证据,例如文件、接口、命令或验证结果。
- 如果需求发生变化,先更新 `CONCEPT.md`,再调整本 TODO。
## 1. 调研与边界
- [x] [CONCEPT: 背景与问题] 阅读相关页面、接口、服务、测试和历史文档,记录当前实现事实。证据:已确认 `agent_runs``agent_tool_calls``semantic_parse_logs``LogDetailView``DigitalEmployeeWorkRecords` 现状。
- [x] [CONCEPT: 目标与非目标] 确认本轮开发范围,写清楚不做项。证据:`CONCEPT.md` 明确只做历史重放,不做调试重跑和 OpenTelemetry。
- [x] [CONCEPT: 风险与开放问题] 标记无法立即确认的依赖、风险和假设。证据:`CONCEPT.md` 风险章节记录脏工作树和数据库初始化依赖。
## 2. 契约与设计
- [x] [CONCEPT: 功能能力] 定义输入、输出、状态、权限和边界条件。证据:`CONCEPT.md` 功能能力章节。
- [x] [CONCEPT: 方案设计] 明确前端、后端、算法、数据的职责边界。证据:`CONCEPT.md` 方案设计章节。
- [x] [CONCEPT: 算法与公式] 补全耗时公式和变量解释。证据:`CONCEPT.md` 算法与公式章节。
- [x] [CONCEPT: 指标与验收] 把验收标准转成可验证的检查点。证据:`CONCEPT.md` 指标与验收章节。
## 3. 后端实现
- [x] [CONCEPT: 后端] 新增 trace 事件模型、schema、repository/service。证据`AgentTraceEvent``agent_trace.py``AgentTraceService`
- [x] [CONCEPT: 后端] 新增 `agent-traces` 只读接口和路由注册。证据:`agent_traces.py` endpoint 与 `router.py` 注册。
- [x] [CONCEPT: 后端] 在 Orchestrator 关键节点写入 trace event。证据`orchestrator.py` 记录接收、会话、语义、路由、回复、失败事件;`orchestrator_execution.py` 记录工具调用事件。
- [x] [CONCEPT: 数据] 实现旧 run fallback 时间线,避免旧数据详情为空。证据:`AgentTraceService.get_trace()` 在无事件时由 `AgentRun``SemanticParseLog``AgentToolCall` 合成只读时间线。
## 4. 算法/规则实现
- [x] [CONCEPT: 算法与规则] 实现 trace 事件排序、耗时计算和状态归一化。证据:`AgentTraceService._next_sequence()``_resolve_duration_ms()``agentTraceViewModel.js`
- [x] [CONCEPT: 结果解释] 输出可读事件标题、摘要、输入输出和错误信息。证据Trace event schema 与 `AgentTraceCenterView.vue` 详情面板。
## 5. 前端实现
- [x] [CONCEPT: 前端] 新增 trace 服务 API 和数据归一化工具。证据:`agentTraces.js``agentTraceViewModel.js`
- [x] [CONCEPT: 前端] 新增 Trace Center 列表与详情视图。证据:`AgentTraceCenterView.vue`
- [x] [CONCEPT: 前端] 从现有日志详情和工作记录补充 trace 跳转入口。证据:`LogDetailView.vue``DigitalEmployeeWorkRecords.vue`
- [x] [CONCEPT: 前端] 实现加载、空态、错误态和刷新。证据:`AgentTraceCenterView.vue` 列表/详情状态与刷新按钮。
- [x] [CONCEPT: 前端] 对齐现有企业级直角、低饱和、密集信息风格。证据:`agent-trace-center-view.css` 使用面板、表格、状态徽标和紧凑信息布局。
## 6. 测试与验证
- [x] [CONCEPT: 测试方案] 补充后端 service/API 定向测试。证据:`test_agent_trace_service.py` 覆盖事件记录、fallback、接口列表和详情。
- [x] [CONCEPT: 测试方案] 补充前端数据归一化测试或可构建验证。证据:`npm.cmd --prefix web run build` 通过。
- [x] [CONCEPT: 测试方案] 在 60s 超时内运行 Docker 后端定向验证。证据:`docker exec ... pytest -q server/tests/test_agent_trace_service.py server/tests/test_agent_runs_service.py`7 passed。
- [x] [CONCEPT: 测试方案] 运行 `npm.cmd --prefix web run build`。证据Vite build 成功。
- [x] [CONCEPT: 指标与验收] 记录验证命令、结果和未覆盖风险。证据:后端测试 7 passed、Vite build 成功、重启后 `/api/v1/agent-traces/{run_id}` live 返回 8 个 fallback 事件;浏览器插件后续不可用,未完成最终截图巡检。
## 7. 文档收尾
- [x] [CONCEPT: 指标与验收] 回看所有验收点,确认均有实现或验证证据。证据:后端 service/API 测试、前端构建、入口接入均已完成。
- [x] [CONCEPT: 风险与开放问题] 更新剩余风险、后续任务和明确不做项。证据:`CONCEPT.md` 保留 OpenTelemetry、跨容器 trace、长期归档为后续待定。
- [x] [CONCEPT: 功能一句话] 确认最终实现没有偏离原始目标。证据:本轮只做 Agent Trace Center未处理 GL/前端状态管理两项待定问题。

View File

@@ -1,58 +0,0 @@
# Agent Plan 文档索引
本目录描述 X-Financial 后续要建设的双 Agent 财务智能架构。
核心目标:
- 建立一套共享的语义本体协议,统一理解用户问题、定时任务和规则触发上下文。
- 建设两套职责边界清晰的 Agent
- Hermes后台数字员工负责内循环定时任务、风险巡检、统计、知识维护。
- 自建 Agent用户流程助手负责用户交互、流程操作、解释、查询、草稿生成。
- 建设 Agent Orchestrator统一负责路由、权限、工具调用、审计和失败处理。
- 让规则中心、MCP、知识库、数据库查询和任务系统使用同一套语义协议。
## 与一周计划的关系
`document/development/agent week plan` 是一周开发路线图,只描述每天要完成的大方向和交付结果。
本目录是具体架构与实现依据,包含:
- 架构设计。
- 数据协议。
- Agent 职责。
- Orchestrator 流程。
- OCR、知识库、规则生命周期。
- 每天 daily 文档会引用到的设计依据。
执行时按这个顺序阅读:
1. 先看 `document/development/agent week plan/MASTER_TODO.md`,确认今天做什么。
2. 再看本目录的架构文档,理解为什么这样做。
3. 最后进入 `document/development/agent week plan/` 对应 Day 文档,在同一份文档中按详细执行清单开发。
推荐阅读顺序:
1. [01_overall_architecture.md](./01_overall_architecture.md)
2. [02_semantic_ontology.md](./02_semantic_ontology.md)
3. [03_agent_responsibilities.md](./03_agent_responsibilities.md)
4. [04_orchestrator_and_runtime_flow.md](./04_orchestrator_and_runtime_flow.md)
5. [05_development_roadmap.md](./05_development_roadmap.md)
6. [06_data_contracts_and_governance.md](./06_data_contracts_and_governance.md)
7. [07_capability_registry.md](./07_capability_registry.md)
8. [08_permission_confirmation.md](./08_permission_confirmation.md)
9. [09_observability_and_trace.md](./09_observability_and_trace.md)
10. [10_evaluation_and_testset.md](./10_evaluation_and_testset.md)
11. [11_ocr_invoice_architecture.md](./11_ocr_invoice_architecture.md)
12. [12_llm_wiki_knowledge_architecture.md](./12_llm_wiki_knowledge_architecture.md)
13. [13_rule_formation_lifecycle.md](./13_rule_formation_lifecycle.md)
14. [14_financial_document_canonical_model.md](./14_financial_document_canonical_model.md)
15. [15_feedback_learning_loop.md](./15_feedback_learning_loop.md)
16. [../agent week plan/00_README.md](<../agent week plan/00_README.md>)
开发原则:
- 先语义协议,后 Agent 能力。
- 先只读和建议,后写入和流程动作。
- 先人工确认,后有限自动化。
- 所有财务关键动作必须可审计、可回滚、可追责。
- 所有 Agent 能力必须注册、分级、可评测、可追踪。

View File

@@ -1,163 +0,0 @@
# 双 Agent 总体架构
## 1. 背景
X-Financial 后续需要同时支持两类智能化能力:
1. 用户主动发起的交互式流程操作。
2. 系统后台自动运行的定时巡检、统计、预警和知识维护。
如果用一个万能 Agent 同时处理这两类任务,风险会很高:
- 用户流程操作需要权限、确认、上下文追问。
- 定时巡检需要稳定批处理、失败重试、审计记录。
- 财务系统不能让大模型直接决定审批、付款、规则上线。
因此建议建设双 Agent 架构:
```text
Hermes Agent
后台数字员工
面向系统内循环
定时、批量、巡检、统计、预警、知识候选
User Agent
自建用户流程助手
面向用户交互
查询、解释、创建草稿、流程操作、审批辅助
```
两套 Agent 共享一套语义本体协议,由 Agent Orchestrator 统一调度。
## 2. 总体架构图
```text
┌──────────────────────┐
│ 用户自然语言 / 定时任务 │
└───────────┬──────────┘
┌──────────────────────┐
│ Semantic Ontology │
│ 语义本体解析层 │
└───────────┬──────────┘
┌──────────────────────┐
│ Agent Orchestrator │
│ 路由 / 权限 / 审计 / 调度 │
└───────┬─────────┬────┘
│ │
┌─────────────▼─┐ ┌─▼──────────────┐
│ Hermes Agent │ │ User Agent │
│ 后台数字员工 │ │ 用户流程助手 │
└───────┬───────┘ └───────┬────────┘
│ │
└──────────┬──────────┘
┌────────────┬───────────┼───────────┬────────────┐
▼ ▼ ▼ ▼ ▼
规则中心 MCP 服务 业务数据库 知识库 任务系统
```
## 3. 核心分层
### 3.1 语义本体层
负责把自然语言或任务配置转成结构化 JSON。
输出不是最终答案,而是统一协议:
```json
{
"domain": "reimbursement",
"scenario": "invoice_validation",
"intent": "explain_risk",
"entities": [],
"time_range": {},
"constraints": {},
"risk_signals": [],
"next_step": "run_rule"
}
```
### 3.2 编排层
Agent Orchestrator 负责:
- 判断应该由 Hermes 还是 User Agent 处理。
- 判断是否需要查数据库、跑规则、调 MCP、检索知识库。
- 检查用户权限。
- 记录审计日志。
- 控制失败重试。
- 对高风险动作要求用户或管理员确认。
### 3.3 Agent 层
Hermes 和 User Agent 不直接决定财务关键状态。
它们负责:
- 理解任务。
- 组织工具调用。
- 汇总工具结果。
- 生成建议、解释、报告、草稿。
### 3.4 能力层
能力层包括:
- 规则中心:管理 `.md` 规则文件、审核、版本。
- MCP封装外部服务如发票验真、银行流水、OCR、差旅平台。
- 数据库查询:查询报销、报账、应收、应付、账款数据。
- 知识库制度文档、FAQ、历史解释、规则说明。
- 任务系统:定时任务、批量任务、重试、运行日志。
## 4. 关键边界
Hermes 可以:
- 定时读取数据。
- 执行规则检查。
- 调 MCP 查询外部状态。
- 生成风险报告。
- 生成知识候选。
- 生成待处理工单。
Hermes 不可以:
- 自动提交报销。
- 自动发起付款。
- 自动审批通过。
- 自动发布知识库正式内容。
- 自动上线规则。
User Agent 可以:
- 帮用户查询状态。
- 帮用户解释风险。
- 帮用户创建报销或付款草稿。
- 帮审批人生成审批意见。
- 在用户确认后调用流程 API。
User Agent 不可以:
- 绕过权限。
- 未确认直接提交关键动作。
- 自动最终审批。
- 自动付款。
- 修改规则审核状态。
## 5. 推荐建设顺序
```text
Step 1: 建立语义本体 JSON 协议
Step 2: 建立规则中心的规则/技能/MCP/任务目录
Step 3: 建立 Orchestrator 路由和审计
Step 4: 建立 User Agent 的只读查询和解释能力
Step 5: 建立 Hermes 的定时任务和报告能力
Step 6: 接入 MCP 和业务数据库
Step 7: 增加用户确认后的流程写入能力
Step 8: 增加知识候选和规则优化闭环
```

View File

@@ -1,457 +0,0 @@
# 语义本体协议设计
## 1. 定位
语义本体协议是用户问题、定时任务、规则中心、MCP、数据库查询和 Agent 之间的统一中间层。
它解决的问题是:
- 用户到底在问哪个业务域?
- 这属于什么场景?
- 用户想做什么?
- 问题中涉及哪些对象?
- 有没有时间、金额、状态、部门等过滤条件?
- 是否涉及风险?
- 下一步应该查知识库、查数据库、跑规则、调 MCP还是追问
## 2. 第一版核心字段
第一版建议只强制落 8 个字段。
```json
{
"domain": "",
"scenario": "",
"intent": "",
"entities": [],
"time_range": {},
"constraints": {},
"risk_signals": [],
"next_step": ""
}
```
### 2.1 domain
一级业务域。
建议枚举:
```text
reimbursement
accounts_receivable
accounts_payable
general_finance
system_operation
```
含义:
- `reimbursement`:报销、差旅、发票、补件。
- `accounts_receivable`:应收账款、客户开票、收款、账龄。
- `accounts_payable`:应付账款、供应商发票、付款、对账。
- `general_finance`:通用财务知识、制度、统计。
- `system_operation`系统巡检、任务运行、规则维护、MCP 健康检查。
### 2.2 scenario
细分场景。
报销:
```text
travel_reimbursement
daily_expense
invoice_validation
attachment_review
policy_overrun
reimbursement_audit
```
应收:
```text
customer_invoice
collection_followup
receivable_aging
payment_matching
bad_debt_risk
contract_receivable
```
应付:
```text
vendor_invoice
payment_request
payable_aging
vendor_reconciliation
invoice_matching
cash_outflow_forecast
```
系统运营:
```text
daily_risk_scan
daily_finance_statistics
knowledge_accumulation
mcp_health_check
rule_quality_review
```
### 2.3 intent
用户或任务的意图。
建议枚举:
```text
query
explain
create
validate
summarize
reconcile
monitor
predict
remind
generate
optimize
```
### 2.4 entities
识别出的业务对象。
统一结构:
```json
{
"type": "invoice",
"value": "INV-202605001",
"normalized_value": "INV-202605001",
"role": "target",
"confidence": 0.92
}
```
常见实体:
```text
employee
department
customer
vendor
invoice
contract
reimbursement_request
payment_order
receipt
bank_transaction
cost_center
project
policy
approval_node
rule
task
```
### 2.5 time_range
统一描述时间。
```json
{
"raw": "上个月",
"start": "2026-04-01",
"end": "2026-04-30",
"granularity": "month"
}
```
Hermes 定时任务也使用同一字段。
例如每日风险巡检:
```json
{
"raw": "昨日",
"start": "2026-05-09",
"end": "2026-05-09",
"granularity": "day"
}
```
### 2.6 constraints
查询、判断或执行条件。
```json
{
"status": "overdue",
"aging_days": ">30",
"amount": {
"operator": ">",
"value": 50000,
"currency": "CNY"
},
"department": "销售部",
"risk_level": ["medium", "high"]
}
```
### 2.7 risk_signals
风险信号。
建议枚举:
```text
duplicate_invoice
missing_attachment
policy_overrun
over_budget
overdue_receivable
bad_debt_risk
vendor_payment_risk
payment_mismatch
contract_mismatch
cashflow_pressure
mcp_unavailable
rule_quality_issue
```
### 2.8 next_step
下一步动作。
建议枚举:
```text
answer
ask_clarification
query_database
run_rule
call_mcp
search_knowledge
create_draft
create_task
generate_report
notify_user
escalate_to_human
```
## 3. 扩展字段
后续可以增加:
```json
{
"schema_version": "1.1",
"confidence": 0.86,
"ambiguity": [],
"missing_slots": [],
"required_capabilities": [],
"normalized_query": "",
"permission_scope": {},
"audit_tags": []
}
```
## 4. 混合语义解析架构
第一版可上线实现不应只依赖关键词和正则。
推荐采用:
```text
输入上下文装配
用户文本 + 页面上下文 + 附件名称 + OCR/VLM 摘要
预抽取
时间、金额、单号、显式对象
LLM 结构化解析
输出 scenario / intent / entities / missing_slots / ambiguity
Schema 校验
JSON 解析、字段枚举、必填校验、类型归一化
规则兜底
模型失败、低置信度或字段缺失时回退到规则解析
澄清追问
低置信度、歧义、缺槽位时不允许直接查库
```
设计原则:
- 模型优先负责“理解意图和场景”。
- 规则优先负责“校验、补全和兜底”。
- 附件名称、OCR、VLM 结果只能作为证据,不等于已确认事实。
- 所有语义输出都必须标记置信度和来源。
## 5. 推荐新增字段
为支持模型优先解析,建议在扩展字段中至少增加:
```json
{
"missing_slots": [],
"ambiguity": [],
"field_confidence": {},
"field_source": {},
"attachment_context": [],
"parse_strategy": "llm_primary_with_rule_fallback"
}
```
字段说明:
- `missing_slots`:还缺哪些关键字段,例如费用类型、单据号、客户单位。
- `ambiguity`:当前可能混淆的理解结果。
- `field_confidence`:字段级置信度,而不是只给整体分数。
- `field_source`:字段来自 `llm``rule``ocr``vlm` 还是 `user_context`
- `attachment_context`:本次可供语义解析使用的附件摘要。
- `parse_strategy`:标记本次是模型主解析还是规则回退。
## 6. 叙述型财务输入
语义层必须支持“不是查询句”的自然叙述。
典型样例:
```text
我今天去客户现场招待了客户花销了1000元
我垫付了打车费和餐费,帮我看看怎么报
上传了三张票,帮我整理成报销草稿
```
这类输入不能默认识别成 `query`
建议默认策略:
- 优先识别为 `reimbursement` 域。
- 场景优先落到 `daily_expense``travel_reimbursement``attachment_review`
- 意图优先落到 `create``generate``validate`
- 缺失关键字段时返回 `ask_clarification`,而不是直接查数据库。
## 7. 模糊短句与澄清规则
以下输入应优先追问:
```text
我要报销
这个为什么还没处理
帮我看一下这个
上传好了,下一步呢
```
处理原则:
- 不允许直接执行工具。
- 不允许直接落到应收、应付查询。
- 必须生成澄清问题。
- 必须在审计中记录触发追问的原因。
扩展原则:
- 先不要把所有字段都做成数据库列。
- 语义结果建议存 JSONB。
- 使用 `schema_version` 管理版本。
- Orchestrator 只依赖稳定字段。
- 新字段以可选方式加入,不影响老任务。
## 4. 示例
### 4.1 用户查询应收账龄
用户问:
```text
上个月哪些客户应收逾期超过 30 天?
```
解析:
```json
{
"domain": "accounts_receivable",
"scenario": "receivable_aging",
"intent": "query",
"entities": [
{
"type": "customer",
"value": "客户",
"role": "group_by"
}
],
"time_range": {
"raw": "上个月",
"start": "2026-04-01",
"end": "2026-04-30",
"granularity": "month"
},
"constraints": {
"aging_days": ">30",
"status": "overdue"
},
"risk_signals": ["overdue_receivable"],
"next_step": "query_database"
}
```
### 4.2 用户解释发票拦截
用户问:
```text
这张发票为什么报销被拦截?
```
解析:
```json
{
"domain": "reimbursement",
"scenario": "invoice_validation",
"intent": "explain",
"entities": [
{
"type": "invoice",
"value": "这张发票",
"role": "target"
}
],
"time_range": {},
"constraints": {},
"risk_signals": ["unknown"],
"next_step": "run_rule"
}
```
### 4.3 Hermes 每日风险巡检
任务配置:
```json
{
"domain": "reimbursement",
"scenario": "daily_risk_scan",
"intent": "monitor",
"entities": [],
"time_range": {
"raw": "昨日"
},
"constraints": {
"risk_level": ["medium", "high"]
},
"risk_signals": [
"duplicate_invoice",
"missing_attachment",
"policy_overrun"
],
"next_step": "run_rule"
}
```

View File

@@ -1,178 +0,0 @@
# Hermes 与自建 Agent 职责边界
## 1. 两套 Agent 的定位
### 1.1 Hermes
Hermes 定位为后台数字员工。
它不直接面向用户聊天,而是在系统后台做内循环工作。
关键词:
```text
定时
批量
巡检
统计
预警
知识维护
规则质量复盘
```
### 1.2 自建 Agent
自建 Agent 定位为用户流程助手。
它直接面对员工、财务人员、审批人和管理员。
关键词:
```text
用户触发
会话式
流程操作
查询解释
草稿生成
审批辅助
用户确认
```
## 2. Hermes 职责
Hermes 负责:
1. 每日风险巡检。
2. 每日报销、报账、账款统计。
3. 应收逾期预警。
4. 应付付款风险预警。
5. 规则命中质量复盘。
6. MCP 健康检查。
7. 知识库候选内容生成。
8. 高风险工单生成。
9. 任务运行报告生成。
Hermes 输出的内容包括:
```text
risk_report
risk_work_items
daily_finance_snapshot
knowledge_candidates
rule_improvement_items
mcp_health_report
task_run_log
```
Hermes 不允许:
1. 自动审批通过。
2. 自动发起付款。
3. 自动提交用户申请。
4. 自动发布正式知识库。
5. 自动上线规则。
6. 直接修改核心财务状态。
## 3. 自建 Agent 职责
自建 Agent 负责:
1. 查询报销单进度。
2. 创建报销或付款草稿。
3. 解释规则拦截原因。
4. 生成审批意见。
5. 检索制度知识。
6. 查询应收应付数据。
7. 帮用户对账。
8. 引导用户补充缺失信息。
9. 在用户确认后调用流程 API。
自建 Agent 输出的内容包括:
```text
natural_language_answer
form_draft
approval_opinion_draft
clarification_question
query_result_summary
next_action_suggestion
```
自建 Agent 不允许:
1. 未经用户确认提交关键动作。
2. 跳过权限校验。
3. 自动最终审批。
4. 自动付款。
5. 修改规则上线状态。
## 4. 权限边界
| 动作 | Hermes | 自建 Agent |
|---|---|---|
| 查询制度知识 | 可以 | 可以 |
| 查询业务数据 | 可以,按任务权限 | 可以,按用户权限 |
| 跑规则 | 可以 | 可以 |
| 调 MCP | 可以 | 可以 |
| 生成报告 | 可以 | 可以 |
| 生成草稿 | 不建议 | 可以 |
| 提交流程 | 不可以 | 用户确认后可以 |
| 审批通过 | 不可以 | 不可以直接做 |
| 发起付款 | 不可以 | 高权限确认后才可做草稿 |
| 发布知识 | 不可以 | 不可以 |
| 上线规则 | 不可以 | 不可以 |
## 5. 共享能力
两套 Agent 共享:
- 语义本体协议。
- 规则中心。
- MCP 服务。
- 知识库。
- 数据库查询服务。
- 审计日志。
- 权限系统。
不共享:
- 运行队列。
- 调度策略。
- 用户会话状态。
- 任务重试状态。
## 6. 示例
### 6.1 Hermes 场景
每日 02:00 自动运行:
```text
每日风险巡检
读取昨日报销、报账、发票、账款数据
执行规则
调用发票验真 MCP
调用账款流水 MCP
生成风险报告
生成风险工单
```
### 6.2 自建 Agent 场景
用户问:
```text
帮我看一下这张差旅报销为什么没通过。
```
处理:
```text
解析语义
查询报销单
读取规则命中
检索制度条款
组织解释
给出补件建议
```

View File

@@ -1,385 +0,0 @@
# Agent Orchestrator 与运行流程
## 1. Orchestrator 定位
Agent Orchestrator 是双 Agent 架构的调度中心。
它不负责生成最终答案,而是负责:
- 接收用户请求或定时任务。
- 调用语义解析。
- 判断处理方。
- 选择工具。
- 检查权限。
- 记录审计。
- 管理失败重试。
- 控制高风险动作确认。
## 2. 运行主流程
```text
输入
用户消息 / 页面按钮 / 定时任务 / 系统事件
上下文装配
页面对象 / 附件名称 / OCR 摘要 / VLM 摘要 / 用户角色 / conversation_id / draft_claim_id
语义解析
LLM 主解析 + 规则兜底,输出 ontology_json
语义校验
confidence / missing_slots / ambiguity / permission 初判
Orchestrator 决策
判断 agent = hermes | user_agent
判断 tool = rule | mcp | db | knowledge | task
权限检查
用户权限 / 任务权限 / 数据范围
业务写入
报销草稿创建 / 报销草稿更新 / 用户确认后提交
工具执行
规则中心 / MCP / 数据库 / 知识库 / 任务系统
Agent 汇总
Hermes 报告 / User Agent 回答
审计记录
保存输入、语义、工具、结果、动作
```
## 3. 路由规则
### 3.1 Hermes 路由
满足以下条件之一,进入 Hermes
```text
source = schedule
source = system_event
intent = monitor
intent = summarize and no active user session
next_step = generate_report and task_type is batch
scenario in daily_risk_scan / knowledge_accumulation / mcp_health_check
```
补充约束:
- 这里的 Hermes 指系统后台真实 Hermes 进程或 Hermes CLI不是前端概念上的 “Hermes 模式”。
- Orchestrator 负责路由、权限、审计和 Trace不负责替代 Hermes 自身执行。
- 当前阶段允许保留本地 fallback但必须预留真实 Hermes 进程调用入口。
### 3.2 User Agent 路由
满足以下条件之一,进入自建 Agent
```text
source = user_message
source = page_action
intent = query / explain / create / validate / reconcile
requires_user_context = true
next_step = ask_clarification
next_step = create_draft
```
### 3.3 工具路由
```text
next_step = query_database
调用数据库查询服务
next_step = run_rule
调用规则中心
next_step = call_mcp
调用 MCP 服务
next_step = search_knowledge
调用知识库检索
next_step = create_task
调用任务系统
next_step = create_expense_claim_draft
创建 expense_claims / expense_claim_items 草稿
next_step = update_expense_claim_draft
回写报销主表、明细和附件关联
next_step = submit_expense_claim
用户确认后更新 expense_claims.status = submitted
next_step = ask_clarification
返回追问
```
### 3.4 低置信度与缺槽位保护
当满足以下任一条件时不允许直接进入数据库、MCP 或高风险流程:
```text
confidence < threshold
missing_slots 非空
ambiguity 非空
输入为叙述型报销,但缺少关键报销信息
```
处理方式:
```text
next_step = ask_clarification
selected_agent = user_agent
tool_count = 0
```
### 3.5 叙述型报销输入保护
像下面这类文本:
```text
我今天去客户现场招待了客户花销了1000元
我垫付了交通费和午餐费
我上传了票据,帮我整理一下
```
不能因为出现“客户”就落到应收查询。
Orchestrator 应依赖语义层返回的 `scenario + intent + missing_slots` 做决策,而不是二次猜测文本关键词。
### 3.6 报销建单与状态流转边界
`scenario = expense` 且已满足最小建单槽位时:
```text
next_step = create_expense_claim_draft
status = draft
```
当用户继续补充金额、地点、客户、参与人、附件时:
```text
next_step = update_expense_claim_draft
status 保持 draft
```
当用户明确说“提交报销”并完成确认时:
```text
next_step = submit_expense_claim
status = submitted
requires_confirmation = true
```
以下状态不应由 User Agent 直接改写:
```text
approved
rejected
paid
```
这些状态应由审批流、财务支付流或受控后台同步更新。
### 3.7 结构化核对回路
`scenario = expense` 且当前仍存在缺槽位、附件待核对或票据需拆单时,不直接返回一段自由文本,而是返回结构化核对结果:
```text
result.review_payload
intent_summary
body_message
slot_cards
risk_briefs
document_cards
claim_groups
confirmation_actions = 取消 / 修改 / 保存草稿或下一步
edit_fields
```
前端正文区只展示简洁提示,右侧展示字段、风险、票据与分单明细。
### 3.8 会话续接与重识别
用户对话不是无状态调用。Orchestrator 需要携带以下会话字段继续当前报销流程:
```text
conversation_id
draft_claim_id
conversation_history
review_action
review_form_values
```
其中:
```text
review_action = edit_review
表示用户基于结构化模板修改识别结果,需要重新进入语义识别
review_action = save_draft
表示信息未补齐,但允许先保存报销草稿
review_action = next_step
表示用户确认当前识别结果,可进入下一步流转
```
## 4. 用户流程示例
用户输入:
```text
上个月哪些客户应收逾期超过 30 天?
```
流程:
```text
Step 1: User Agent 接收消息
Step 2: semantic_parser 输出 ontology_json
Step 3: Orchestrator 识别 domain = accounts_receivable
Step 4: next_step = query_database
Step 5: 权限检查用户是否可看应收数据
Step 6: 查询应收账龄表
Step 7: User Agent 汇总结果
Step 8: 返回客户清单、金额、逾期天数、风险说明
```
## 5. Hermes 任务示例
任务:
```text
每日风险巡检
```
流程:
```text
Step 1: 任务调度器在 02:00 触发
Step 2: Orchestrator 构造 ontology_json
Step 3: 路由给 Hermes
Step 4: Hermes 拉取昨日业务快照
Step 5: 执行规则中心规则
Step 6: 调用 MCP 验真、账款流水
Step 7: 生成风险报告
Step 8: 写入风险工单
Step 9: 记录任务日志
Step 10: 通知财务风控组
```
### 5.1 Hermes 后台执行方式
推荐最小形态:
```text
任务系统 / 手动触发 API
Orchestrator 生成 run_id、任务上下文、权限信息
后端调用系统 Hermes CLI 或 Hermes 后台进程
Hermes 执行知识同步 / 风险巡检 / 规则草稿形成
结果回写 AgentRun / ToolCall / 审计日志
```
约束:
- Hermes 运行使用系统级配置,不在任务代码里再写一套模型配置。
- Hermes 运行失败要记录 stderr 或等价错误摘要。
- Hermes 输出的知识候选和规则草稿必须回写为结构化结果,不只保留终端文本。
## 5A. 用户报销建单示例
用户输入:
```text
我今天去客户现场招待了客户花销了1000元
```
流程:
```text
Step 1: User Agent 接收消息
Step 2: semantic_parser 输出 ontology_json
Step 3: Orchestrator 判断 scenario = expense, intent = draft
Step 4: 若缺客户、参与人、附件,则 next_step = ask_clarification
Step 5: 补齐最小槽位后next_step = create_expense_claim_draft
Step 6: 创建 expense_claims / expense_claim_items
Step 7: 若有附件,则挂接 document_assets / expense_item_documents
Step 8: 用户确认提交后next_step = submit_expense_claim
Step 9: 更新 expense_claims.status = submitted
Step 10: 写入 AgentRun、ToolCall、AuditLog
```
## 6. 审计日志
每次 Agent 运行都应该写入审计。
建议字段:
```json
{
"id": "",
"source": "user_message | schedule | system_event",
"agent": "hermes | user_agent",
"user_id": "",
"task_id": "",
"ontology_json": {},
"tools_called": [],
"permission_scope": {},
"result_summary": "",
"action_taken": "",
"requires_confirmation": false,
"created_at": ""
}
```
建议补充 Trace 字段:
```json
{
"semantic_provider": "",
"semantic_model": "",
"semantic_prompt_version": "",
"semantic_parse_strategy": "llm_primary | rule_fallback",
"semantic_fallback_reason": "",
"semantic_latency_ms": 0
}
```
## 7. 失败处理
### 7.1 用户交互失败
```text
数据库查询失败
返回“暂时无法查询”,记录错误
缺少关键字段
返回追问
权限不足
返回无权限说明
MCP 不可用
返回降级说明,必要时生成待处理项
```
### 7.2 Hermes 任务失败
```text
任务失败
自动重试 3 次
部分 MCP 失败
标记 partial_success
数据不完整
生成异常任务日志
连续失败
通知管理员
```

View File

@@ -1,458 +0,0 @@
# 分阶段开发计划
## Phase 0准备阶段
目标:统一概念和边界,不写复杂功能。
### Step 0.1 明确术语
产出:
- 规则:`.md` 审查规则文件。
- 技能:可复用的 Agent 能力,如审批意见生成、风险解释。
- MCP外部服务连接。
- 任务:定时或批量运行的后台作业。
- Hermes后台数字员工。
- User Agent用户流程助手。
- Orchestrator调度和路由层。
- Ontology语义本体协议。
### Step 0.2 冻结第一版语义字段
第一版只强制 8 个字段:
```text
domain
scenario
intent
entities
time_range
constraints
risk_signals
next_step
```
### Step 0.3 建立设计文档
产出:
- 本目录所有文档。
- 后续数据库表设计草案。
- API 合同草案。
## Phase 1任务规则中心基础建设
目标:先把管理后台搭起来。
### Step 1.1 完成前端信息架构
页签:
```text
规则 / 技能 / MCP / 任务
```
规则详情:
- Markdown 编辑器。
- 审核人。
- 审核状态。
- 版本列表。
- 版本切换确认。
技能详情:
- 技能配置。
- 输入上下文。
- 输出契约。
- 测试样例。
- 依赖能力。
MCP 详情:
- 服务地址。
- 鉴权方式。
- 权限范围。
- 健康检查。
- 调用记录。
任务详情:
- Cron。
- 运行窗口。
- 输入范围。
- 产出对象。
- 最近运行。
### Step 1.2 建立后端基础模型
建议表:
```text
agent_rules
agent_skills
agent_mcp_services
agent_tasks
agent_asset_versions
agent_asset_reviews
```
第一阶段可以先不做完整执行,只做 CRUD。
### Step 1.3 规则版本与审核
规则上线流程:
```text
草稿
提交审核
审核通过
上线
```
关键约束:
- 没有审核人不能上线。
- 没有审核通过不能上线。
- 上线必须生成新版本。
- 历史版本只读。
## Phase 2OCR 与财务单据标准模型
目标:让发票、附件、报销单和账款流水先标准化。
### Step 2.1 附件上传与文件分类
识别:
- 发票。
- 行程单。
- 合同。
- 付款凭证。
- 审批截图。
### Step 2.2 OCR MCP 接入
把附件转成结构化字段。
### Step 2.3 Invoice 标准模型
统一 OCR、MCP、用户填写和业务系统字段。
### Step 2.4 人工修正
允许财务人员修正 OCR 字段,并写入反馈池。
### Step 2.5 规则中心接入 OCR 结果
重复发票、附件完整性、金额不一致等规则开始使用标准模型。
## Phase 3语义本体服务
目标:用户问题和任务配置都能转成 ontology_json。
### Step 3.1 建立 semantic_parser API
接口:
```text
POST /api/v1/semantic/parse
```
输入:
```json
{
"source": "user_message",
"text": "上个月哪些客户应收逾期超过 30 天?",
"context": {}
}
```
输出:
```json
{
"domain": "accounts_receivable",
"scenario": "receivable_aging",
"intent": "query",
"entities": [],
"time_range": {},
"constraints": {},
"risk_signals": [],
"next_step": "query_database"
}
```
### Step 3.2 建立模型优先解析器
要求:
- 使用运行时模型配置,而不是写死单一 provider。
- 输入包括文本、上下文、附件摘要和预抽取字段。
- 输出必须是结构化 JSON而不是自由文本。
- 输出必须经过 Schema 校验。
- 模型失败时必须回退到规则解析。
### Step 3.3 建立 ontology schema 表
建议表:
```text
semantic_ontology_schemas
semantic_parse_logs
```
字段:
```text
id
schema_version
schema_json
status
created_at
updated_at
```
### Step 3.4 建立字段级校验与澄清策略
至少支持:
- 缺少费用类型时追问。
- 缺少业务对象时追问。
- 短句或模糊句时追问。
- 叙述型报销输入默认走 create/generate而不是 query。
- 低置信度时禁止工具执行。
### Step 3.5 建立解析测试集
至少覆盖:
- 报销规则解释。
- 差旅报销创建。
- 叙述型报销创建。
- 发票验真。
- 应收逾期查询。
- 应付付款状态。
- 每日风险巡检。
- 知识库维护。
- 模糊短句追问。
- 附件输入解析。
## Phase 4LLM Wiki 知识库
目标让制度文档、FAQ、审批经验可被 Agent 检索和引用。
### Step 4.1 文档解析与分块
上传 PDF、Word、Excel 后抽取正文并 chunk。
### Step 4.2 元数据与向量索引
为知识块打 domain、scenario、tags、版本。
### Step 4.3 知识检索 API
User Agent 可以基于语义本体查询知识。
### Step 4.4 知识候选审核
Hermes 生成 FAQ 或条款候选,人工审核后发布。
## Phase 5Orchestrator 基础版
目标:基于 ontology_json 做确定性路由。
### Step 5.1 建立路由规则
输入:
```text
source
domain
scenario
intent
next_step
```
输出:
```text
agent = hermes | user_agent
tools = []
permission_required = []
```
### Step 5.2 建立工具网关
第一批工具:
```text
rule_engine.run
knowledge.search
database.query
mcp.call
task.create
```
### Step 5.3 建立审计日志
所有请求都记录:
- 原始输入。
- 语义 JSON。
- 路由结果。
- 工具调用。
- 输出摘要。
- 错误信息。
## Phase 6User Agent 第一版
目标:先做只读和解释,不做强写入。
### Step 6.1 支持制度问答
流程:
```text
用户问题
-> semantic_parse
-> search_knowledge
-> User Agent 生成回答
```
### Step 6.2 支持规则解释
流程:
```text
用户问为什么被拦截
-> semantic_parse
-> run_rule
-> search_knowledge
-> User Agent 解释风险原因
```
### Step 6.3 支持业务查询
先支持:
- 报销单状态查询。
- 应收账龄查询。
- 应付付款状态查询。
### Step 6.4 支持草稿生成
只生成草稿,不直接提交。
```text
用户确认前不写核心状态
```
## Phase 7Hermes 第一版
目标:让后台数字员工开始跑任务。
### Step 7.1 每日风险巡检
输入:
- 昨日单据。
- 发票。
- 附件。
- 付款流水。
输出:
- 风险报告。
- 风险工单。
- 风险统计。
### Step 7.2 每日财务统计
统计:
- 报销金额。
- 报账金额。
- 应收账龄。
- 应付账龄。
- 付款状态。
- 账款异常。
### Step 7.3 知识候选积累
来源:
- 审批意见。
- 驳回原因。
- 高频问答。
- 规则误报反馈。
输出:
- FAQ 候选。
- 规则优化建议。
- 制度变更摘要。
## Phase 8MCP 接入
目标:让 Agent 能安全调用外部系统。
优先接入:
1. 发票验真 MCP。
2. 附件 OCR MCP。
3. 银行流水 MCP。
4. 差旅平台 MCP。
5. ERP/付款状态 MCP。
每个 MCP 必须有:
- 服务地址。
- 鉴权方式。
- 权限范围。
- 超时设置。
- 降级策略。
- 健康检查。
- 调用日志。
## Phase 9规则形成与反馈闭环
目标:让系统持续变聪明,但不失控。
闭环:
```text
Hermes 发现问题
-> 生成规则优化建议
-> 管理员审核
-> 更新规则
-> User Agent 使用新规则解释
-> 反馈继续进入 Hermes
```
关键限制:
- Hermes 只生成候选。
- 管理员审核后才能发布。
- 所有规则变更有版本。
- 所有上线动作有审核人。
### Step 9.1 规则候选池
Hermes 从制度、风险案例、反馈中生成规则候选。
### Step 9.2 规则测试样例
每条规则上线前必须有测试样例。
### Step 9.3 反馈池
收集 OCR 修正、规则误报、Agent 回答反馈。
### Step 9.4 质量看板
统计误报率、修正率、回答满意度、MCP 失败率。

View File

@@ -1,445 +0,0 @@
# 数据契约与治理要求
## 1. 推荐数据表
### 1.1 语义本体
```text
semantic_ontology_schemas
```
字段:
```text
id
schema_version
schema_json
status
created_by
created_at
updated_at
```
```text
semantic_parse_logs
```
字段:
```text
id
source
user_id
raw_text
ontology_json
confidence
parse_strategy
created_at
```
### 1.2 Agent 资产
```text
agent_rules
agent_skills
agent_mcp_services
agent_tasks
```
通用字段:
```text
id
code
name
description
status
owner
reviewer
config_json
created_at
updated_at
```
### 1.3 版本与审核
```text
agent_asset_versions
```
字段:
```text
id
asset_type
asset_id
version
content
change_note
created_by
created_at
```
```text
agent_asset_reviews
```
字段:
```text
id
asset_type
asset_id
version
reviewer
review_status
review_note
reviewed_at
```
### 1.4 运行日志
```text
agent_runs
```
字段:
```text
id
agent
source
task_id
user_id
ontology_json
status
started_at
finished_at
result_summary
error_message
```
```text
agent_tool_calls
```
字段:
```text
id
run_id
tool_type
tool_name
request_json
response_json
status
duration_ms
created_at
```
### 1.5 财务业务主表
```text
expense_claims
expense_claim_items
accounts_receivable
accounts_payable
approval_records
```
治理要求:
- `expense_claims` 作为报销主表,不再继续扩张 `reimbursement_requests`
- `expense_claim_items` 作为报销明细最小粒度OCR 匹配、风险识别、票据挂接都优先挂到该粒度。
- `accounts_receivable``accounts_payable` 保持独立,避免因为 Agent 语义层接入而混用口径。
### 1.6 票据与文件资产表
```text
document_assets
document_asset_versions
document_derivatives
expense_item_documents
document_access_logs
```
职责:
- `document_assets`:原始附件主索引
- `document_asset_versions`:原件版本留痕
- `document_derivatives`:预览件、缩略图、脱敏件、逐页图片
- `expense_item_documents`:报销明细与票据关联
- `document_access_logs`:预览、下载、导出审计
### 1.7 OCR、验真与风险表
```text
document_ocr_results
invoice_structured_records
invoice_verification_records
risk_events
risk_actions
```
职责:
- `document_ocr_results`:每次 OCR 执行快照
- `invoice_structured_records`:标准化发票字段
- `invoice_verification_records`:发票验真结果留痕
- `risk_events`:风险命中事实
- `risk_actions`:风险处置动作
## 2. API 契约
### 2.1 语义解析
```text
POST /api/v1/semantic/parse
```
请求:
```json
{
"source": "user_message",
"text": "这张发票为什么被拦截?",
"context": {
"user_id": "emp_001",
"current_page": "reimbursement_detail"
}
}
```
响应:
```json
{
"domain": "reimbursement",
"scenario": "invoice_validation",
"intent": "explain",
"entities": [],
"time_range": {},
"constraints": {},
"risk_signals": ["unknown"],
"parse_strategy": "llm_primary",
"next_step": "run_rule"
}
```
### 2.2 Orchestrator 执行
```text
POST /api/v1/agent/orchestrate
```
请求:
```json
{
"source": "user_message",
"ontology": {},
"context": {}
}
```
响应:
```json
{
"agent": "user_agent",
"tools_called": [],
"answer": "",
"requires_confirmation": false,
"audit_id": ""
}
```
### 2.3 文件上传契约
```text
POST /api/v1/documents/upload
```
请求:
```json
{
"biz_domain": "expense",
"biz_object_type": "expense_claim",
"biz_object_id": "claim_001",
"upload_source": "user_workbench",
"files": [
{
"filename": "invoice.jpg",
"mime_type": "image/jpeg"
}
]
}
```
响应:
```json
{
"documents": [
{
"document_id": "",
"version_no": 1,
"storage_status": "stored",
"ocr_status": "pending"
}
]
}
```
### 2.4 Hermes 任务
```text
POST /api/v1/hermes/tasks/run
```
请求:
```json
{
"task_code": "daily_risk_scan",
"ontology": {},
"dry_run": false,
"context_json": {
"folder": "报销制度",
"changed_only": true,
"force": false
}
}
```
响应:
```json
{
"run_id": "",
"status": "accepted"
}
```
补充:
- Hermes 任务应优先调用系统后台 Hermes CLI 或等价 Hermes 进程。
- `changed_only=true` 时,只处理知识库中发生变化的文档。
- 文档变化判断至少包含 `original_name``stored_name``sha256``version_number``updated_at`
- 若文档无变化,应返回 `unchanged_skipped`,而不是重新形成 LLM Wiki。
## 3. 安全原则
### 3.1 最小权限
Agent 调工具时不能使用超级权限。
权限来源:
- 用户权限
- 任务权限
- 服务账号权限
### 3.2 高风险动作确认
以下动作必须确认:
- 提交报销
- 发起付款
- 生成正式审批意见
- 发布规则
- 发布知识库
- 创建外部通知
### 3.3 审计不可省略
必须记录:
- 谁触发
- 输入是什么
- 解析结果是什么
- 调了哪些工具
- 输出是什么
- 是否确认
### 3.4 文件存储治理
必须遵守:
- 原始文件二进制不落业务主表,不存入大字段 blob。
- 所有文件必须有 `storage_provider``storage_key``sha256``file_size_bytes``mime_type`
- 原件不可覆盖,只能新增版本。
- 删除默认是解除业务关联或逻辑删除,物理删除必须走审计流程。
- 对象存储访问必须使用签名 URL 或后端代理,不直接暴露固定公网地址。
### 3.5 敏感数据治理
对于发票、行程单、合同、付款凭证中的敏感信息:
- 应支持脱敏衍生件
- 应记录查看与下载行为
- 应区分申请人、审批人、财务、管理员可见范围
- 应支持争议单据 `legal_hold` 保留策略
### 3.6 AI 证据治理
Agent 和 OCR 相关能力必须遵守:
- 未经 OCR/VLM 实际解析,不得假设附件内容已知。
- Agent 输出若引用发票金额、号码、日期,必须能追溯到 `invoice_structured_records` 或人工修正记录。
- 风险解释若引用“重复报销”“金额不一致”等判断,必须能追溯到 `risk_events.evidence_json`
## 4. 数据质量要求
### 4.1 关键唯一性
- `expense_claims.claim_no` 唯一
- `document_assets.sha256` 可重复但必须可检索
- `document_asset_versions(document_id, version_no)` 唯一
- `invoice_structured_records.duplicate_fingerprint` 必须可索引
### 4.2 时间与状态字段
- 所有业务主表必须有 `created_at``updated_at`
- 文件上传、OCR、验真、风控、处置必须有独立时间戳
- 状态字段应使用受控枚举,不允许前端自由拼写
### 4.3 可追溯性
任一笔报销单、发票或风险结论,至少应能追到:
- 原始输入文本
- 原始附件
- 结构化结果
- 规则或模型判断
- 人工修正动作
## 5. 实施优先级
第一优先级:
- `expense_claims`
- `expense_claim_items`
- `document_assets`
- `document_asset_versions`
- `expense_item_documents`
第二优先级:
- `document_ocr_results`
- `invoice_structured_records`
- `invoice_verification_records`
- `document_derivatives`
第三优先级:
- `risk_events`
- `risk_actions`
- `document_access_logs`
实施原则:
- 先确保“能收、能存、能找回原件”
- 再确保“能识别、能验真、能回填”
- 最后做“能解释、能审计、能批量巡检”

View File

@@ -1,198 +0,0 @@
# Capability Registry 能力注册中心
## 1. 为什么需要能力注册中心
双 Agent 架构里会出现很多能力:
- 规则文件。
- 技能。
- MCP 服务。
- 数据库查询。
- 知识库检索。
- 定时任务。
- 报告生成。
如果 Orchestrator 直接在代码里硬编码这些能力,会导致:
- 能力越来越多后难维护。
- 无法统一权限。
- 无法统一版本。
- 无法统一输入输出格式。
- Hermes 和 User Agent 复用困难。
因此建议建立 Capability Registry。
它的定位是:
```text
所有可被 Agent 调用的能力目录
```
## 2. 能力类型
建议第一版支持:
```text
rule
skill
mcp
task
database_query
knowledge_search
report_generator
notification
```
含义:
- `rule`:审查规则,通常是 `.md` 文件或规则配置。
- `skill`:智能能力,如审批意见生成、风险解释。
- `mcp`:外部服务连接。
- `task`:定时或批量任务。
- `database_query`:受控数据库查询能力。
- `knowledge_search`:知识库检索能力。
- `report_generator`:报告生成能力。
- `notification`:通知能力。
## 3. 能力注册结构
建议结构:
```json
{
"id": "cap_rule_duplicate_invoice",
"code": "duplicate_invoice_rule",
"name": "重复报销识别规则",
"capability_type": "rule",
"domain": "reimbursement",
"scenarios": ["invoice_validation", "reimbursement_audit"],
"intents": ["validate", "explain", "monitor"],
"input_schema": {},
"output_schema": {},
"permission_required": ["reimbursement:read", "risk:write"],
"risk_level": "high",
"owner": "财务风控组",
"version": "v1.9",
"status": "active",
"requires_confirmation": false,
"created_at": "",
"updated_at": ""
}
```
## 4. 与语义本体的匹配关系
Orchestrator 根据 ontology_json 匹配能力。
示例:
```json
{
"domain": "reimbursement",
"scenario": "invoice_validation",
"intent": "explain",
"risk_signals": ["duplicate_invoice"],
"next_step": "run_rule"
}
```
可以匹配:
```text
重复报销识别规则
发票验真 MCP
风险解释技能
制度知识库检索
```
## 5. 能力匹配优先级
建议顺序:
```text
Step 1: next_step 决定能力大类
Step 2: domain 限定业务域
Step 3: scenario 限定场景
Step 4: risk_signals 匹配具体规则
Step 5: intent 匹配技能
Step 6: permission_required 校验权限
Step 7: status 必须 active
Step 8: version 使用当前上线版本
```
## 6. 数据表建议
```text
agent_capabilities
```
字段:
```text
id
code
name
capability_type
domain
scenario_json
intent_json
input_schema_json
output_schema_json
permission_json
risk_level
owner
current_version
status
requires_confirmation
config_json
created_at
updated_at
```
## 7. 开发步骤
### Step 1: 先注册静态能力
先把现有规则、技能、MCP、任务写入 Registry。
不需要一开始做复杂 UI。
### Step 2: Orchestrator 改为查 Registry
从:
```text
if next_step = run_rule then call duplicate_invoice_rule
```
改为:
```text
query capabilities where type = rule and scenario = invoice_validation
```
### Step 3: 加权限过滤
只返回当前用户或任务有权限调用的能力。
### Step 4: 加版本选择
默认使用 active 版本。
历史版本只用于回放和调试。
### Step 5: 加健康状态
MCP、任务、数据库查询能力应有健康状态。
不可用时 Orchestrator 走降级策略。
## 8. 治理要求
- 所有能力必须有 owner。
- 高风险能力必须有 reviewer。
- 所有能力必须有输入输出 schema。
- 所有能力必须有状态。
- 下线能力不能被 Orchestrator 调用。
- 能力版本变更必须写入审计。

View File

@@ -1,214 +0,0 @@
# 权限与确认引擎
## 1. 目标
Agent 不能只靠提示词判断能不能执行动作。
财务系统需要独立的权限与确认引擎:
```text
Permission Engine
Confirmation Engine
```
它们负责:
- 判断用户是否能看某类数据。
- 判断任务是否能调用某个能力。
- 判断动作是否需要确认。
- 判断动作是否禁止自动执行。
## 2. 动作风险分级
建议按 L0-L5 分级。
### L0 只读查询
例子:
- 查询制度。
- 查询单据状态。
- 查询规则说明。
- 查询任务运行记录。
要求:
- 需要权限。
- 不需要确认。
### L1 生成建议
例子:
- 生成审批意见建议。
- 生成风险解释。
- 生成规则优化建议。
要求:
- 需要权限。
- 不写业务状态。
- 不需要确认,但要标记为建议。
### L2 生成草稿
例子:
- 生成报销草稿。
- 生成付款申请草稿。
- 生成知识库候选。
要求:
- 需要权限。
- 写入草稿区。
- 不进入正式流程。
### L3 用户确认后提交
例子:
- 用户确认后提交报销。
- 审批人确认后写入审批意见。
- 用户确认后发起补件。
要求:
- 必须二次确认。
- 必须记录确认人。
- 必须记录确认前后内容。
### L4 管理员确认后发布
例子:
- 发布规则。
- 发布知识库。
- 启用 MCP。
- 启用任务。
要求:
- 必须管理员确认。
- 必须有审核记录。
- 必须有版本。
### L5 禁止自动执行
例子:
- 自动最终审批。
- 自动付款。
- 自动绕过风控。
- 自动修改核心财务状态。
要求:
- Agent 永远不能直接执行。
## 3. 权限判断输入
```json
{
"user_id": "emp_001",
"agent": "user_agent",
"source": "user_message",
"action": "create_reimbursement_draft",
"domain": "reimbursement",
"resource": {
"type": "reimbursement_request",
"id": ""
},
"capability": "travel_reimbursement_create"
}
```
## 4. 权限判断输出
```json
{
"allowed": true,
"risk_level": "L2",
"requires_confirmation": false,
"reason": "",
"permission_scope": {
"departments": ["current_user"],
"data_masking": false
}
}
```
## 5. 确认弹窗策略
需要确认的动作必须显示:
- 动作名称。
- 影响对象。
- 关键字段。
- 执行后果。
- 是否可撤销。
- 确认人。
示例:
```json
{
"title": "确认提交报销申请",
"action": "submit_reimbursement",
"summary": "将提交差旅报销单 TR-202605001金额 ¥3,280。",
"risk_level": "L3",
"confirm_button": "确认提交"
}
```
## 6. Hermes 权限
Hermes 使用服务账号,不使用个人账号。
建议拆分权限:
```text
hermes:risk_scan
hermes:finance_statistics
hermes:knowledge_candidate
hermes:mcp_health_check
```
Hermes 默认只允许:
- 读脱敏快照。
- 跑规则。
- 调只读 MCP。
- 写报告、候选、工单。
Hermes 不允许:
- 写正式审批状态。
- 写正式付款状态。
- 发布规则。
- 发布知识。
## 7. User Agent 权限
User Agent 继承当前用户权限。
例如:
- 员工只能看自己的报销。
- 部门负责人可以看本部门。
- 财务可以看授权范围内数据。
- 管理员可以管理规则、任务、MCP。
User Agent 不能扩大用户权限。
## 8. 开发步骤
```text
Step 1: 定义 action risk level
Step 2: 建立 Permission Engine 接口
Step 3: 所有工具调用前接入权限判断
Step 4: L3/L4 动作接入确认弹窗
Step 5: 审计记录确认内容
Step 6: 增加权限测试用例
```

View File

@@ -1,186 +0,0 @@
# 可观测性与 Agent Run Trace
## 1. 目标
Agent 系统必须可追踪、可回放、可解释。
财务系统中尤其需要回答:
- 为什么 Agent 得出这个结论?
- 用了哪个模型?
- 用了哪个规则版本?
- 调用了哪些 MCP
- 查了哪些数据?
- 谁确认了动作?
- 失败在哪里?
## 2. Agent Run Trace
每次 Agent 运行都生成一个 run_id。
建议结构:
```json
{
"run_id": "",
"source": "user_message",
"agent": "user_agent",
"user_id": "emp_001",
"raw_input": "",
"ontology_json": {},
"route_decision": {},
"permission_result": {},
"tool_calls": [],
"final_output": "",
"status": "success",
"started_at": "",
"finished_at": ""
}
```
## 3. 需要记录的版本
每次运行都要记录:
```text
ontology_schema_version
semantic_parser_prompt_version
model_name
model_version
rule_version
skill_version
mcp_version
knowledge_snapshot_version
orchestrator_version
```
原因:
用户可能问:
```text
为什么昨天和今天的结论不一样?
```
只有记录版本,才能解释。
## 4. Tool Call Trace
每个工具调用都记录:
```json
{
"tool_call_id": "",
"run_id": "",
"tool_type": "mcp",
"tool_name": "invoice_verify",
"request_json": {},
"response_json": {},
"status": "success",
"duration_ms": 820,
"error_message": ""
}
```
敏感字段应脱敏。
## 5. 运行状态
建议枚举:
```text
pending
running
success
partial_success
failed
cancelled
waiting_confirmation
```
## 6. Hermes 可观测性
Hermes 任务需要额外记录:
```text
task_code
schedule_time
data_snapshot_id
records_scanned
rules_executed
mcp_calls
risk_items_generated
knowledge_candidates_generated
retry_count
```
示例:
```json
{
"task_code": "daily_risk_scan",
"records_scanned": 2146,
"rules_executed": 8,
"mcp_calls": 436,
"risk_items_generated": 19,
"status": "success"
}
```
## 7. User Agent 可观测性
User Agent 需要额外记录:
```text
conversation_id
page_context
user_confirmation
draft_created
business_object_id
```
## 8. 前端审计视图
建议后续增加“Agent 运行记录”页面。
展示:
- 运行时间。
- Agent 类型。
- 用户或任务。
- 语义解析结果。
- 调用工具。
- 运行状态。
- 耗时。
- 错误。
详情页展示:
- 原始输入。
- 本体 JSON。
- 路由决策。
- 工具调用链。
- 最终输出。
## 9. 告警
需要告警的情况:
- Hermes 任务连续失败。
- MCP 健康检查失败。
- 语义解析低置信度比例过高。
- 某规则误报率过高。
- Agent 调用耗时异常。
- 权限拒绝次数异常。
## 10. 开发步骤
```text
Step 1: 增加 agent_runs 表
Step 2: 增加 agent_tool_calls 表
Step 3: Orchestrator 每次执行创建 run_id
Step 4: 工具网关记录 tool call
Step 5: 前端增加运行记录页面
Step 6: 增加异常告警规则
```

View File

@@ -1,198 +0,0 @@
# 评测集与质量控制
## 1. 为什么需要评测集
语义解析、本体字段、Agent 路由、规则命中都不能只靠人工感觉。
每次修改 prompt、模型、规则或路由逻辑都应该运行评测集。
目标:
- 检查 domain 是否识别正确。
- 检查 scenario 是否识别正确。
- 检查 intent 是否识别正确。
- 检查 next_step 是否正确。
- 检查是否应该追问。
- 检查是否错误调用高风险工具。
## 2. 第一版评测集规模
建议第一版至少 300 条。
```text
报销问题80 条
应收问题60 条
应付问题60 条
制度问答40 条
风险解释30 条
定时任务20 条
模糊问题10 条
叙述型报销20 条
附件输入10 条
```
## 3. 评测样例结构
```json
{
"id": "eval_001",
"input": "上个月哪些客户应收逾期超过 30 天?",
"expected": {
"domain": "accounts_receivable",
"scenario": "receivable_aging",
"intent": "query",
"next_step": "query_database"
},
"required_entities": ["customer"],
"notes": "应识别为应收账龄查询"
}
```
## 4. 评测指标
### 4.1 字段准确率
```text
domain_accuracy
scenario_accuracy
intent_accuracy
next_step_accuracy
field_level_f1
clarification_accuracy
```
### 4.2 工具路由准确率
```text
tool_route_accuracy
permission_decision_accuracy
confirmation_decision_accuracy
narrative_misroute_rate
```
### 4.3 安全指标
```text
unsafe_action_rate
missing_confirmation_rate
permission_bypass_rate
low_confidence_unsafe_tool_rate
```
这些指标必须接近 0。
## 5. 低置信度处理
语义解析输出应包含:
```json
{
"confidence": 0.62,
"missing_slots": ["time_range"],
"ambiguity": ["应收逾期还是审批逾期"]
}
```
当置信度低于阈值:
```text
confidence < 0.75
不执行工具
返回追问
```
## 6. 模糊问题样例
用户问:
```text
这个为什么还没处理?
```
不能直接执行查询。
应该追问:
```text
你是想查询报销单、应收款还是付款申请的处理状态?
```
叙述型报销样例:
```json
{
"id": "eval_reimbursement_narrative_001",
"input": "我今天去客户现场招待了客户花销了1000元",
"expected": {
"domain": "reimbursement",
"scenario": "daily_expense",
"intent": "create",
"next_step": "ask_clarification"
},
"required_entities": ["amount"],
"notes": "不能错误路由到应收查询"
}
```
## 7. 回归测试流程
每次改动以下内容都要跑评测:
- semantic parser 模型或 provider。
- semantic parser prompt。
- ontology schema。
- Orchestrator 路由。
- 规则中心匹配逻辑。
- MCP 能力注册。
- 模型版本。
流程:
```text
Step 1: 加载评测集
Step 2: 批量调用 semantic_parse
Step 3: 批量调用 route_decision
Step 4: 对比 expected
Step 5: 输出准确率报告
Step 6: 阻止低于阈值的发布
```
## 8. 发布阈值
建议第一版阈值:
```text
domain_accuracy >= 95%
intent_accuracy >= 90%
next_step_accuracy >= 90%
unsafe_action_rate = 0
missing_confirmation_rate = 0
narrative_misroute_rate <= 1%
low_confidence_unsafe_tool_rate = 0
```
## 9. 评测数据管理
建议文件结构:
```text
server/tests/fixtures/semantic_eval/
reimbursement.jsonl
accounts_receivable.jsonl
accounts_payable.jsonl
risk_explain.jsonl
scheduled_tasks.jsonl
```
每行一个样例。
## 10. 开发步骤
```text
Step 1: 建立 JSONL 评测集格式
Step 2: 写 50 条人工样例
Step 3: 接入 semantic_parse 批测脚本
Step 4: 输出 markdown/html 评测报告
Step 5: 扩展到 300 条
Step 6: 接入 CI 或手动发布检查
```

View File

@@ -1,376 +0,0 @@
# OCR 票据识别架构
## 1. 定位
OCR 票据识别不是一个简单的图片转文字功能。
它在 X-Financial 中承担四件事:
1. 把用户上传的附件变成结构化票据信息。
2. 为规则中心提供可判断的字段。
3. 为 User Agent 和 Hermes 提供可解释的证据。
4. 为后续审计、复核、争议处理保留可回溯原件。
因此 OCR 应作为独立能力纳入 Capability Registry。
```text
capability_type = mcp | document_processor
capability_code = invoice_ocr
```
## 2. 总体链路
```text
附件上传
文件落盘 / 对象存储
文件分类
OCR 识别
字段结构化
票据类型归一化
发票验真 MCP
与报销明细匹配
规则中心检查
人工修正
修正结果沉淀
```
关键原则:
- 文件先持久化,再做 OCR不允许只在内存里跑完就丢。
- 原件不可覆盖,只能新增版本。
- Agent 不得假设图片内容已知;只有 OCR/VLM 实际解析后才能引用附件内容。
## 3. 阶段拆分
### Phase A附件接入与文件分类
目标:先识别上传的是什么。
输入:
- 图片
- PDF
- Excel
- Word
- 压缩包
输出:
```json
{
"document_type": "invoice",
"mime_type": "image/png",
"page_count": 1,
"confidence": 0.91
}
```
分类结果:
```text
invoice
itinerary
contract
payment_receipt
approval_screenshot
other
```
### Phase BOCR 字段提取
目标:从图片或 PDF 中提取票据字段。
结构:
```json
{
"invoice_code": "",
"invoice_number": "",
"seller_name": "",
"seller_tax_no": "",
"buyer_name": "",
"buyer_tax_no": "",
"issue_date": "",
"total_amount": 0,
"tax_amount": 0,
"currency": "CNY",
"ocr_confidence": 0.88
}
```
### Phase C字段归一化
目标:不同 OCR 服务返回不同字段名,必须统一。
示例:
```text
发票号码 / invoiceNo / invoice_number
-> invoice_number
```
金额统一:
```json
{
"raw": "¥1,280.00",
"value": 1280.00,
"currency": "CNY"
}
```
### Phase D验真与状态检查
调用发票验真 MCP。
输出:
```json
{
"verify_status": "verified",
"voided": false,
"red_reversed": false,
"verified_at": ""
}
```
### Phase E与报销明细匹配
对比:
- 发票金额 vs 报销金额
- 开票日期 vs 费用日期
- 销售方 vs 商户
- 发票类型 vs 费用类型
输出:
```json
{
"match_status": "matched",
"mismatch_fields": [],
"match_confidence": 0.94
}
```
### Phase F人工修正与回流
OCR 结果必须允许人工修正。
修正内容进入反馈池:
```json
{
"field": "invoice_number",
"before": "12345B",
"after": "123456",
"corrected_by": "finance_user",
"corrected_at": ""
}
```
## 4. 文件存储策略
### 4.1 为什么不能直接把文件塞进数据库
- 原始票据、合同、行程单体积大,数据库行膨胀明显。
- 预览件、缩略图、逐页图片、脱敏件都属于衍生文件,不适合和业务行混存。
- 财务原件需要版本留痕和不可变追溯,文件系统或对象存储更适合。
结论:
- 文件二进制存文件系统或对象存储。
- 数据库仅保存元数据、索引、版本、OCR 结果、验真结果、访问审计和业务关联。
### 4.2 开发环境目录方案
根目录使用后端配置中的 `STORAGE_ROOT_DIR`
建议目录:
```text
<STORAGE_ROOT_DIR>/
finance-documents/
expense_claim/
2026/
05/
<claim_id>/
<document_id>/
v1/
original/
source.jpg
preview/
preview.pdf
pages/
page-1.png
thumbs/
thumb.webp
ocr/
ocr-1.json
verify/
verify-1.json
```
说明:
- `claim_id` 为空时,可先挂到 `draft/<conversation_id>/<document_id>/...`,待正式建单后再回填业务关联。
- `v1``v2` 表示文件版本,不允许直接覆盖 `v1`
- 原始文件名用于展示,真实定位依赖 `storage_key``sha256`
### 4.3 生产环境存储方案
生产环境建议使用:
- MinIO
- S3
- 阿里云 OSS
- 腾讯云 COS
对象存储推荐键名:
```text
finance-documents/expense_claim/2026/05/<claim_id>/<document_id>/v1/original/source.jpg
finance-documents/expense_claim/2026/05/<claim_id>/<document_id>/v1/preview/preview.pdf
finance-documents/expense_claim/2026/05/<claim_id>/<document_id>/v1/thumbs/thumb.webp
```
数据库必须保存:
```text
storage_provider
storage_bucket
storage_key
sha256
file_size_bytes
mime_type
current_version_no
```
### 4.4 原件、版本与衍生件规则
- 原件不可变:上传后不得覆盖。
- 替换附件只能新增 `document_asset_versions` 记录。
- OCR 原始输出、验真响应、预览件、缩略图都作为衍生件管理。
- 删除操作默认只允许逻辑删除业务关联,不允许物理删除原件。
- 命中审计或争议流程的单据可切换到 `legal_hold` 保留策略,暂停清理。
### 4.5 去重与追溯
- 每个原始文件必须计算 `sha256`
- 同一个 `sha256` 可提示重复上传,但不能自动覆盖旧版本。
- 发票查重不能只靠文件哈希,还要结合 `invoice_code + invoice_number + issue_date + total_amount`
## 5. 数据模型建议
推荐配套表:
```text
document_assets
document_asset_versions
document_derivatives
document_ocr_results
invoice_structured_records
invoice_verification_records
expense_item_documents
document_access_logs
```
各表职责:
- `document_assets`:文件主索引
- `document_asset_versions`:原件版本
- `document_derivatives`:缩略图、预览、逐页图片、脱敏件
- `document_ocr_results`:每次 OCR 执行结果
- `invoice_structured_records`:标准化票据字段
- `invoice_verification_records`:验真结果
- `expense_item_documents`:报销明细与票据挂接
- `document_access_logs`:文件查看、下载、导出审计
## 6. 与规则中心关系
OCR 输出供规则使用:
```text
重复报销识别规则
作废发票检查规则
发票抬头异常规则
附件完整性规则
金额不一致规则
OCR 低置信度补录规则
```
规则读取原则:
- 读标准化字段,不直接依赖某个 OCR 服务的原始字段名。
- 需要追证时,从 `document_assets``document_asset_versions` 找原件。
- 需要解释时,从 `document_ocr_results``invoice_verification_records` 给证据。
## 7. 与 Agent 关系
User Agent 使用 OCR
- 解释发票为什么被拦截
- 帮用户补充发票信息
- 提醒上传清晰附件
- 根据 OCR 结果自动回填报销草稿
Hermes 使用 OCR
- 夜间批量验真
- 扫描重复票据
- 统计发票异常趋势
- 回刷历史低置信度票据
## 8. 安全与审计要求
### 8.1 访问控制
- 原始票据预览、下载应按用户角色控制。
- 财务、审批人、申请人看到的文件范围可以不同。
- 对象存储不要暴露永久公网链接,统一走签名 URL 或后端代理下载。
### 8.2 敏感信息处理
- 身份证、银行卡、手机号等敏感字段如被识别,应支持脱敏预览件。
- 对外展示尽量用衍生件,不直接暴露原件。
### 8.3 审计要求
必须记录:
- 谁上传了原件
- 谁触发了 OCR
- 谁查看或下载了原件
- 谁修正了 OCR 结果
- 谁发起了验真
- 哪次风险判断引用了哪些票据
## 9. 开发阶段建议
```text
Step 1: 附件上传与 document_assets / document_asset_versions 落库
Step 2: 本地文件目录方案打通
Step 3: 接入 OCR MCP 或 OCR 服务
Step 4: 结构化字段归一化
Step 5: 发票验真 MCP
Step 6: 与 expense_claim_items 匹配
Step 7: 风险规则中心接入
Step 8: 人工修正界面
Step 9: Hermes 夜间批量 OCR 与验真巡检
```
当前阶段优先级:
- 先把“文件原件可存、可找、可追溯”做实。
- 再把 OCR 和验真接进来。
- 最后再做大规模自动巡检和脱敏导出。

View File

@@ -1,221 +0,0 @@
# LLM Wiki 知识库架构
## 1. 定位
LLM Wiki 不是简单的文件库。
它是给 Agent 使用的知识底座负责把制度、FAQ、审批经验、规则说明转成可检索、可引用、可版本化的知识。
## 2. 总体链路
```text
文档上传
格式解析
正文抽取
分块 Chunking
元数据标注
向量索引
条款抽取
知识候选
人工审核
发布 Wiki
Agent 检索引用
```
## 2.1 目录约束
LLM Wiki 解析产物不能与原始制度文件混放。
推荐目录:
```text
/app/server/storage/knowledge/<folder>/ 原始知识文件
/app/server/storage/knowledge/.llm_wiki/ 解析产物根目录
/app/server/storage/knowledge/.llm_wiki/documents/<document_id>/
document.json
text.md
chunks.json
clauses.json
knowledge_candidates.json
rule_candidates.json
/app/server/storage/knowledge/.llm_wiki/index.json
/app/server/storage/knowledge/.llm_wiki/sync_runs.json
```
约束:
- 原始文件目录只存原件,不存解析碎片。
- LLM Wiki 目录只存结构化产物,不反向覆盖原件。
- 所有解析产物必须能按 `document_id` 回溯到原始文件。
## 3. 知识类型
```text
policy_document
faq
rule_explanation
approval_case
risk_case
operation_manual
system_notice
```
## 4. 知识块结构
```json
{
"chunk_id": "",
"document_id": "",
"title": "",
"content": "",
"domain": "reimbursement",
"scenario": "travel_reimbursement",
"tags": ["差旅", "住宿标准"],
"effective_date": "",
"version": "v1.0",
"source_page": 4,
"embedding_id": "",
"status": "published"
}
```
## 5. 条款抽取
Hermes 可以从制度文档中抽取条款候选。
示例:
```json
{
"clause_type": "amount_limit",
"domain": "reimbursement",
"scenario": "travel_reimbursement",
"condition": {
"city_tier": "一线城市",
"employee_grade": "P5"
},
"limit": {
"amount": 800,
"currency": "CNY",
"period": "night"
},
"source": "差旅制度 2026 第 4 页"
}
```
该结果不直接变成规则,先进入规则候选池。
## 5.1 增量形成策略
LLM Wiki 不应按天无脑全量重建。
每个文档都应维护签名:
```json
{
"document_id": "",
"original_name": "",
"stored_name": "",
"sha256": "",
"version_number": 1,
"updated_at": ""
}
```
只有在以下任一条件发生时,才重建对应文档的 LLM Wiki
- `original_name` 变更。
- `stored_name` 变更。
- `sha256` 变更。
- `version_number` 变更。
- `updated_at` 变更,视为人工修改。
如果以上均未变化:
- 本次文档状态应记为 `unchanged_skipped`
- 不重新抽取正文。
- 不重新分块。
- 不重新生成知识候选或规则候选。
## 6. Wiki 发布流程
```text
草稿知识
Hermes 生成候选
知识管理员审核
发布
Agent 可检索
```
## 7. 与 User Agent 的关系
User Agent 用 Wiki
- 回答制度问题。
- 给风险解释提供条款依据。
- 给审批意见生成引用。
- 帮用户理解流程。
## 8. 与 Hermes 的关系
Hermes 用 Wiki
- 每日知识候选生成。
- 发现制度与规则不一致。
- 生成规则优化建议。
- 生成 FAQ 候选。
补充要求:
- Hermes 对制度文档的处理默认是增量同步,不是每日全量重建。
- Hermes 应先检查知识库签名,再决定是否需要重建某个文档的 Wiki。
- Hermes 形成的是候选与草稿,不是正式发布内容。
## 9. 数据模型建议
```text
knowledge_documents
knowledge_chunks
knowledge_embeddings
knowledge_candidates
knowledge_reviews
knowledge_versions
```
当前最小落地允许先以文件索引实现:
```text
.llm_wiki/index.json
.llm_wiki/sync_runs.json
.llm_wiki/documents/<document_id>/document.json
```
后续再平滑迁移到数据库或向量库。
## 10. 开发阶段建议
```text
Step 1: 文档上传和文件管理
Step 2: 文本抽取和分块
Step 3: 元数据标注
Step 4: 向量索引
Step 5: 知识检索 API
Step 6: User Agent 问答引用
Step 7: Hermes 知识候选生成
Step 8: 人工审核发布
Step 9: 条款抽取和规则候选
```

View File

@@ -1,194 +0,0 @@
# 规则形成生命周期
## 1. 定位
规则不是凭空写出来的。
它应来自:
- 制度文档。
- 历史审批。
- 风险案例。
- OCR 识别结果。
- MCP 验真结果。
- 用户反馈。
- Hermes 分析。
## 2. 总体闭环
```text
制度文档 / 历史审批 / 风险案例 / 用户反馈
Hermes 分析
规则候选
人工审核
规则 .md
测试样例
版本发布
规则执行
命中反馈
规则优化
```
## 3. 规则候选结构
```json
{
"candidate_id": "",
"source_type": "policy_document",
"domain": "reimbursement",
"scenario": "invoice_validation",
"risk_signal": "duplicate_invoice",
"suggested_rule_name": "重复报销识别规则",
"rule_markdown_draft": "",
"evidence": [],
"confidence": 0.86,
"created_by": "hermes"
}
```
补充约束:
- `rule_markdown_draft` 不能是任意自由文本,必须符合固定模板。
- 规则候选应同时携带机器可读 JSON 草稿,例如 `runtime_rule`
- JSON 草稿只能从受控模板族中选择,不允许 Hermes 自创字段结构后直接进入规则中心。
## 4. 规则 Markdown 推荐结构
```markdown
# 规则名称
## 目标
## 适用范围
## 输入字段
## 判断规则
## 输出
## 测试样例
## 管理员备注
```
推荐再补一段模板元信息:
```markdown
## 模板信息
- 模板键:`travel_standard_v1`
- 来源文档公司支出管理办法2024
- Hermes 置信度0.86
- 审核人:张三
```
## 4.1 规则 JSON 推荐结构
规则中心不应只有 Markdown。
应同时提供可执行 JSON 编辑区,至少支持:
```json
{
"kind": "policy_rule_draft",
"version": 1,
"template_key": "travel_standard_v1",
"rule_name": "差旅住宿标准草稿规则",
"scenario": "travel_reimbursement",
"review_required": true,
"conditions": {},
"actions": {},
"source_document_name": "公司支出管理办法2024"
}
```
治理要求:
- Markdown 负责给人看。
- JSON 负责给运行时和规则引擎看。
- 两者必须成对维护,不能只改其中一份。
- JSON 变更也必须走版本和审核。
## 4.2 模板族约束
Hermes 只能从白名单模板中选,不允许自由生成任意规则结构。
第一版建议模板:
```text
travel_standard_v1
expense_amount_limit_v1
attachment_requirement_v1
general_policy_v1
```
如果制度条款不适合自动规则化:
- 允许只生成 `knowledge_candidate`
- 或只生成 `general_policy_v1` 草稿并要求人工补齐
- 不能为了“有结果”而编造可执行规则
## 5. 审核要求
规则上线必须满足:
- 有审核人。
- 有版本。
- 有测试样例。
- 有来源依据。
- 有回滚方案。
补充:
- Hermes 生成规则默认只能是 `draft`
- Hermes 不能直接覆盖当前 `active` 线上规则。
- Hermes 如发现制度更新,应优先生成新的候选或草稿版本,仍需人工审核后再上线。
## 6. 规则执行反馈
每次规则运行应记录:
```text
rule_id
rule_version
input_snapshot
hit_result
risk_level
operator_feedback
false_positive
false_negative
```
## 7. 规则优化来源
```text
误报反馈
漏报反馈
审批人修改意见
Hermes 每日复盘
制度文档更新
MCP 新字段可用
```
## 8. 开发阶段建议
```text
Step 1: 规则 .md 编辑和版本
Step 2: 规则审核上线
Step 3: 规则运行日志
Step 4: 人工反馈误报/漏报
Step 5: Hermes 生成规则候选
Step 6: 规则候选审核
Step 7: 规则测试样例管理
Step 8: 规则质量看板
```

View File

@@ -1,646 +0,0 @@
# 财务单据标准模型
## 1. 为什么需要标准模型
OCR、MCP、用户填写、业务数据库可能都描述同一张发票但字段名和格式不同。
如果没有标准模型:
- 规则无法复用。
- Agent 难以解释。
- Hermes 难以批量统计。
- MCP 返回结果难以合并。
这里要区分三层:
- 标准模型:定义 Agent、规则、MCP、OCR、数据库之间统一交换的数据结构。
- 业务数据库表:定义 MVP 阶段真正落库存储、查询和统计所依赖的业务表。
- 文件存储对象定义原始票据、预览件、OCR 中间产物、验真结果附件的存储位置与版本规则。
如果只有标准模型没有业务表和文件资产表User Agent 无法真正发起报销如果只有数据库表没有统一标准模型语义解析、规则解释、OCR 回填和 Hermes 巡检会越来越混乱。
## 2. 标准对象
第一版建议定义这些对象:
```text
Invoice
Receipt
ExpenseClaim
PaymentRequest
AccountsReceivableRecord
AccountsPayableRecord
BankTransaction
Contract
Customer
Vendor
Employee
CostCenter
DocumentAsset
RiskEvent
```
说明:
- 对外语义层建议统一使用 `ExpenseClaim` 概念,不再把“报销申请”和“报销单据”拆成两个平行主概念。
- 现有代码中仍有 `reimbursement_requests`MVP 阶段不建议再继续扩张该表,而应以 `expense_claims` 作为报销主表。
- `reimbursement_requests` 可保留用于兼容旧页面或审批联动,但新能力默认挂到 `expense_claims`
## 3. Invoice 标准模型
```json
{
"invoice_id": "",
"invoice_code": "",
"invoice_number": "",
"invoice_type": "",
"seller_name": "",
"seller_tax_no": "",
"buyer_name": "",
"buyer_tax_no": "",
"issue_date": "",
"total_amount": 0,
"tax_amount": 0,
"currency": "CNY",
"verify_status": "",
"ocr_confidence": 0,
"source_document_id": ""
}
```
## 4. ExpenseClaim 标准模型
```json
{
"claim_id": "",
"claim_no": "",
"employee_id": "",
"employee_name": "",
"department_id": "",
"department_name": "",
"cost_center_code": "",
"project_code": "",
"expense_type": "",
"reason": "",
"location": "",
"amount": 0,
"currency": "CNY",
"status": "",
"occurred_at": "",
"submitted_at": "",
"approval_stage": "",
"items": [],
"attachments": [],
"risk_flags": []
}
```
说明:
- `reason``location``occurred_at` 是报销语义判断、规则解释、风险识别的最小必要字段。
- 一张报销单通常包含多条费用明细,标准模型中允许聚合,数据库层必须拆到明细表。
- `attachments` 指向文件资产,不直接嵌入二进制文件。
## 5. AccountsReceivableRecord 标准模型
```json
{
"ar_id": "",
"document_no": "",
"customer_id": "",
"customer_name": "",
"contract_no": "",
"invoice_no": "",
"amount_receivable": 0,
"amount_received": 0,
"amount_outstanding": 0,
"currency": "CNY",
"due_date": "",
"posting_date": "",
"status": "",
"aging_days": 0,
"risk_flags": []
}
```
## 6. AccountsPayableRecord 标准模型
```json
{
"ap_id": "",
"document_no": "",
"vendor_id": "",
"vendor_name": "",
"invoice_no": "",
"amount_payable": 0,
"amount_paid": 0,
"amount_outstanding": 0,
"currency": "CNY",
"due_date": "",
"posting_date": "",
"status": "",
"aging_days": 0,
"risk_flags": []
}
```
## 7. BankTransaction 标准模型
```json
{
"transaction_id": "",
"bank_account": "",
"transaction_date": "",
"amount": 0,
"currency": "CNY",
"counterparty_name": "",
"summary": "",
"matched_object_type": "",
"matched_object_id": "",
"match_status": ""
}
```
## 8. MVP 真实业务表设计
标准模型不等于数据库表,但 MVP 至少要有以下真实表,才能支撑 Day 5 用户报销对话、Day 6 风险巡检和后续审批/验真闭环。
### 8.1 设计原则
- 报销主数据统一落在 `expense_claims`,不再新建第三套“报销主表”。
- 原始票据文件二进制不进数据库,只存元数据和关联信息。
- OCR 结果、发票结构化结果、验真结果、风险事件要分表存,避免把所有字段塞进一个 JSON。
- 所有表都要能被 Agent 解释,也要能被 Hermes 批量扫表。
- `reimbursement_requests` 进入兼容态,不作为新能力主干表继续扩展。
### 8.2 报销主表 `expense_claims`
用途:
- 作为用户报销会话最终落单的主业务对象。
- 承接语义层补槽后的草稿、提交、审批、打回、归档状态。
建议字段:
```text
id string(36) PK
claim_no string(50) UK, 报销单号
source string(30) 来源: agent/web/import/api
title string(200) 报销标题
employee_id string(64) 申请人 ID
employee_name string(100) 申请人姓名
department_id string(64) 部门 ID
department_name string(100) 部门名
company_code string(50) 公司编码
cost_center_code string(50) 成本中心
project_code string(50) 项目编码
expense_type string(50) 费用大类
reason text 事由
location string(100) 地点
amount numeric(12,2) 报销总金额
currency string(10) 币种
invoice_count int 附件票据数
attachment_count int 附件总数
occurred_start_at timestamptz 发生开始时间
occurred_end_at timestamptz 发生结束时间
submitted_at timestamptz 提交时间
status string(30) draft/submitted/approved/rejected/paid
status_changed_at timestamptz 最近状态变更时间
status_changed_by string(64) 最近状态变更人
status_change_note text 状态变更备注
approval_stage string(50) 当前审批节点
risk_level string(20) none/low/medium/high
risk_flags_json json 风险标记快照
conversation_id string(64) 对话会话 ID
created_by string(64) 创建人
updated_by string(64) 更新人
created_at timestamptz
updated_at timestamptz
```
说明:
- 现有模型已有一部分字段,后续只做增量扩展即可。
- `occurred_start_at``occurred_end_at` 比单一 `occurred_at` 更适合差旅、接待等跨时段报销。
### 8.2.1 报销状态流转建议
建议状态:
```text
draft
submitted
approved
rejected
paid
```
建议流转:
```text
语义补槽完成
-> 创建 expense_claims 草稿
-> status = draft
用户继续补充字段 / 上传附件
-> 更新 expense_claims / expense_claim_items / expense_item_documents
-> status 仍为 draft
用户明确确认提交
-> status = submitted
-> 写入 submitted_at / status_changed_at / status_changed_by
审批流结果回写
-> status = approved 或 rejected
付款完成回写
-> status = paid
```
边界:
- User Agent 可以创建 `draft`,也可以在用户确认后提交到 `submitted`
- User Agent 不应直接把状态改为 `approved``rejected``paid`
- 所有状态变化都应写审计日志,必要时保留 `status_change_note`
### 8.3 报销明细表 `expense_claim_items`
用途:
- 表达一单多明细。
- 作为 OCR 发票比对、重复报销识别、风险定位的最小粒度。
建议字段:
```text
id string(36) PK
claim_id string(36) FK -> expense_claims.id
line_no int 明细序号
item_date date 费用发生日期
item_type string(50) 费用小类
item_reason text 明细事由
item_location string(100) 明细地点
merchant_name string(200) 商户/酒店/餐厅
customer_name string(200) 客户单位
participants_json json 参与人员
transport_type string(50) 交通方式
item_amount numeric(12,2) 明细金额
tax_amount numeric(12,2) 税额
currency string(10)
invoice_match_status string(30) unmatched/partial/matched
risk_level string(20)
risk_flags_json json
remark text
created_at timestamptz
updated_at timestamptz
```
说明:
- 现有 `invoice_id` 单字段不足以覆盖多张附件挂同一明细的情况,后续应改为关联表。
### 8.4 票据资产主表 `document_assets`
用途:
- 作为所有原始附件的主索引表。
- 支持报销单、报销明细、审批、验真、风控证据等多对象挂载。
建议字段:
```text
id string(36) PK
biz_domain string(30) expense/ap/ar/common
biz_object_type string(50) expense_claim/expense_item/approval_record
biz_object_id string(36) 业务对象 ID
document_type string(50) invoice/receipt/itinerary/contract/other
document_subtype string(50) vat_special/taxi/train/hotel/meal 等
source string(30) upload/agent/import/system
original_filename string(255)
mime_type string(100)
file_ext string(20)
page_count int
file_size_bytes bigint
sha256 string(64) 去重与追溯
storage_provider string(30) local/minio/s3/oss/cos
storage_bucket string(100) 本地模式可为空
storage_key string(500) 指向当前有效版本原件
current_version_no int
classification_status string(30) pending/success/failed
ocr_status string(30) pending/running/success/failed
virus_scan_status string(30) pending/clean/infected
retention_policy string(30) finance_default/legal_hold/manual
uploaded_by string(64)
uploaded_at timestamptz
created_at timestamptz
updated_at timestamptz
```
### 8.5 票据版本表 `document_asset_versions`
用途:
- 保留原始文件和后续重新上传版本。
- 允许“修正”但不允许覆盖原始证据。
建议字段:
```text
id string(36) PK
document_id string(36) FK -> document_assets.id
version_no int 1,2,3...
is_current bool
change_reason string(100) replace/rotate/desensitize/reupload
original_filename string(255)
mime_type string(100)
file_size_bytes bigint
sha256 string(64)
storage_provider string(30)
storage_bucket string(100)
storage_key string(500)
uploaded_by string(64)
uploaded_at timestamptz
created_at timestamptz
```
### 8.6 衍生文件表 `document_derivatives`
用途:
- 存储缩略图、预览 PDF、逐页图片、脱敏件等衍生产物。
建议字段:
```text
id string(36) PK
document_version_id string(36) FK -> document_asset_versions.id
derivative_type string(50) thumb/preview/page_image/desensitized
page_no int 可空
mime_type string(100)
file_size_bytes bigint
storage_provider string(30)
storage_bucket string(100)
storage_key string(500)
created_by string(64)
created_at timestamptz
```
### 8.7 OCR 结果表 `document_ocr_results`
用途:
- 保留每次 OCR 原始结果、模型版本、置信度和错误信息。
- 支持后续重跑 OCR 与人工纠错对比。
建议字段:
```text
id string(36) PK
document_id string(36) FK -> document_assets.id
document_version_id string(36) FK -> document_asset_versions.id
ocr_engine string(50) paddle/aliyun/tencent/openai 等
ocr_model string(100)
run_no int 第几次 OCR
status string(30) success/failed/partial
language string(20)
raw_text text
raw_result_json json
structured_result_json json
confidence numeric(5,4)
error_message text
started_at timestamptz
finished_at timestamptz
created_at timestamptz
```
### 8.8 发票结构化表 `invoice_structured_records`
用途:
- 将发票核心字段标准化后独立存储,便于查重、验真、规则计算。
建议字段:
```text
id string(36) PK
document_id string(36) FK -> document_assets.id
ocr_result_id string(36) FK -> document_ocr_results.id
invoice_code string(50)
invoice_number string(50)
invoice_type string(50)
seller_name string(200)
seller_tax_no string(50)
buyer_name string(200)
buyer_tax_no string(50)
issue_date date
total_amount numeric(12,2)
tax_amount numeric(12,2)
currency string(10)
check_code string(100)
is_red_invoice bool
is_electronic bool
ocr_confidence numeric(5,4)
normalized_status string(30) normalized/manual_corrected
duplicate_fingerprint string(100) 发票号+代码+金额+日期
created_at timestamptz
updated_at timestamptz
```
### 8.9 发票验真记录表 `invoice_verification_records`
用途:
- 保留每次调用税局/第三方验真服务的结果,支持追溯。
建议字段:
```text
id string(36) PK
invoice_record_id string(36) FK -> invoice_structured_records.id
verification_channel string(50) tax_mcp/third_party/manual
request_payload_json json
response_payload_json json
verify_status string(30) verified/unverified/voided/error
voided bool
red_reversed bool
verified_amount numeric(12,2)
verified_issue_date date
error_code string(50)
error_message text
verified_by string(64)
verified_at timestamptz
created_at timestamptz
```
### 8.10 明细与票据关联表 `expense_item_documents`
用途:
- 解决一条明细可关联多张票据、一张票据也可能支撑多条拆分明细的场景。
建议字段:
```text
id string(36) PK
claim_id string(36) FK -> expense_claims.id
claim_item_id string(36) FK -> expense_claim_items.id
document_id string(36) FK -> document_assets.id
relation_type string(30) evidence/invoice/boarding_pass/receipt
allocated_amount numeric(12,2) 分摊到该明细的金额
match_status string(30) unmatched/partial/matched
match_confidence numeric(5,4)
created_at timestamptz
updated_at timestamptz
```
### 8.11 风险事件表 `risk_events`
用途:
- 记录风险命中,而不是只在主表里塞一个 `risk_flags_json`
- 作为 Agent 解释“为什么拦截”的核心依据。
建议字段:
```text
id string(36) PK
biz_domain string(30) expense/ap/ar
biz_object_type string(50) expense_claim/expense_item/invoice
biz_object_id string(36)
risk_code string(50) duplicate_invoice/amount_mismatch 等
risk_name string(100)
risk_level string(20) low/medium/high
hit_source string(30) rule/agent/hermes/manual
evidence_json json
status string(30) open/confirmed/resolved/ignored
detected_at timestamptz
detected_by string(64)
resolved_at timestamptz
resolved_by string(64)
resolution_note text
created_at timestamptz
updated_at timestamptz
```
### 8.12 风险处置表 `risk_actions`
用途:
- 记录每次人工确认、驳回、忽略、要求补件等处置动作。
建议字段:
```text
id string(36) PK
risk_event_id string(36) FK -> risk_events.id
action_type string(30) confirm/reject/ignore/request_more
action_note text
operator_id string(64)
operator_name string(100)
created_at timestamptz
```
### 8.13 文件访问审计表 `document_access_logs`
用途:
- 记录谁看过、下载过、导出过原始票据。
- 支撑财务审计和数据安全追溯。
建议字段:
```text
id string(36) PK
document_id string(36) FK -> document_assets.id
document_version_id string(36) FK -> document_asset_versions.id
action string(30) preview/download/export/delete
operator_id string(64)
operator_name string(100)
operator_role string(50)
client_ip string(64)
user_agent string(255)
trace_id string(64)
created_at timestamptz
```
## 9. 表关系建议
```text
expense_claims
└─ expense_claim_items
└─ expense_item_documents
└─ document_assets
└─ document_asset_versions
└─ document_derivatives
└─ document_ocr_results
└─ invoice_structured_records
└─ invoice_verification_records
risk_events -> 可指向 expense_claims / expense_claim_items / invoice_structured_records
risk_actions -> risk_events
document_access_logs -> document_assets / document_asset_versions
```
原则:
- 主业务对象和文件资产解耦。
- OCR、验真、风险都挂在文件资产或业务对象之上不把责任塞到一个巨表。
- 文件版本和业务关系分离,避免替换附件时把历史证据冲掉。
## 10. 与现有表的衔接策略
当前代码中已经存在:
- `expense_claims`
- `expense_claim_items`
- `reimbursement_requests`
建议策略:
- `expense_claims` 继续作为未来报销主表。
- `expense_claim_items` 增量扩字段并替换当前单一 `invoice_id` 直连方式。
- `reimbursement_requests` 暂不删除,但冻结扩表。
- 如旧流程仍引用 `reimbursement_requests`,可在过渡期建立:
- `request_no -> claim_no` 对照字段
- 或由 `approval_records` 同时支持两类来源对象
不建议做法:
- 再新建第四张“报销申请主表”。
- 把原始发票图片以 blob 方式存进 `expense_claims`
- 把 OCR、验真、风控结果全塞进一个 JSON 大字段。
## 11. 实施顺序建议
Phase 1
- 扩展 `expense_claims`
- 扩展 `expense_claim_items`
- 新增 `document_assets`
- 新增 `document_asset_versions`
- 新增 `expense_item_documents`
Phase 2
- 新增 `document_ocr_results`
- 新增 `invoice_structured_records`
- 新增 `invoice_verification_records`
- 新增 `document_derivatives`
Phase 3
- 新增 `risk_events`
- 新增 `risk_actions`
- 新增 `document_access_logs`
Phase 4
- 逐步弱化 `reimbursement_requests`
- 将 Agent 草稿、审批、OCR、验真、风控全收敛到 `expense_claims` 体系
## 12. 对 Agent 的直接收益
- 用户说“我要报销”时Agent 能先创建 `expense_claims` 草稿,再持续补槽。
- 用户上传票据后,系统有明确的 `document_assets``expense_item_documents` 可挂载。
- OCR 和验真结果不是一次性临时输出,而是可追溯、可回放、可审计的长期资产。
- Agent 回答“为什么被拦截”时,可以直接引用 `risk_events` 和票据证据,不再靠拼字符串解释。

View File

@@ -1,119 +0,0 @@
# 反馈闭环与持续学习
## 1. 定位
Agent 系统必须能从人工反馈中持续变好。
反馈来源:
- OCR 人工修正。
- 规则误报/漏报。
- 审批人修改意见。
- 用户对回答的反馈。
- Hermes 风险复盘。
- MCP 调用失败和降级。
## 2. 反馈类型
```text
ocr_correction
rule_false_positive
rule_false_negative
agent_answer_feedback
approval_opinion_edit
knowledge_answer_feedback
mcp_failure_feedback
task_result_feedback
```
## 3. 反馈结构
```json
{
"feedback_id": "",
"feedback_type": "rule_false_positive",
"source_object_type": "rule_run",
"source_object_id": "",
"before": {},
"after": {},
"comment": "",
"created_by": "",
"created_at": ""
}
```
## 4. 反馈流向
```text
人工反馈
反馈池
Hermes 聚类分析
候选改进项
人工审核
更新规则 / 知识 / OCR 映射 / Prompt
```
## 5. 反馈不直接自动生效
反馈只能生成候选,不直接修改线上规则。
必须人工审核:
- 规则修改。
- 知识发布。
- Prompt 修改。
- OCR 字段映射调整。
## 6. Hermes 每日反馈复盘
Hermes 每日任务:
```text
读取昨日反馈
聚类相似问题
统计误报高发规则
统计低评分回答
生成优化候选
```
输出:
```text
rule_improvement_candidates
knowledge_update_candidates
ocr_mapping_candidates
prompt_improvement_notes
```
## 7. 质量指标
建议监控:
```text
ocr_correction_rate
rule_false_positive_rate
rule_false_negative_rate
agent_answer_like_rate
agent_answer_rewrite_rate
knowledge_no_hit_rate
mcp_failure_rate
```
## 8. 开发阶段建议
```text
Step 1: 增加反馈按钮和反馈表
Step 2: OCR 修正写入反馈池
Step 3: 规则误报/漏报反馈
Step 4: Agent 回答反馈
Step 5: Hermes 每日反馈聚类
Step 6: 生成优化候选
Step 7: 人工审核发布
Step 8: 建立质量看板
```

View File

@@ -1,77 +0,0 @@
# Agent Week Plan 一周开发路线图
本目录现在同时承接:
- 一周路线图
- 每天 daily 文档
- 每天的详细执行清单
原独立执行细则目录已合并进各 Day 文档,不再单独维护。
## 文档分工
| 目录 | 职责 | 读者 |
| --- | --- | --- |
| `agent week plan` | 一周节奏、每天目标、验收门槛、详细执行清单、阻塞记录、日终交接 | 产品、架构、Codex、开发、验收 |
| `agent plan` | 架构设计、协议、流程、治理、标准模型、能力边界 | 架构、开发、评审 |
## 使用方式
1. 先读 [MASTER_TODO.md](./MASTER_TODO.md),确认 7 天节奏和当前状态。
2. 打开当天 daily 文档。
3. 在同一份 daily 文档里按顺序阅读:
今天的大开发点 -> 当前完成情况 -> 当天验收门槛 -> 详细执行清单 -> 阻塞记录 -> 日终交接。
4. 如需设计依据,再跳到 `agent plan` 对应架构文档。
5. 完成一个最小项后,再把该项改成完成态,而不是代码写完就直接算过。
## 完成标记规则
未完成:
```md
- [ ] 建立 AgentAsset 数据模型
```
完成后:
```md
- [x] ~~建立 AgentAsset 数据模型~~
```
执行要求:
- [ ] 每次只处理一个最小 TODO。
- [ ] 完成后先自测,再改成 `[x]`
- [ ] 改成 `[x]` 时,同时用 `~~` 画线。
- [ ] 不能因为代码写完就标完成,必须满足该 TODO 的验收证据。
- [ ] 遇到阻塞时,在当天文档的“阻塞记录”下新增说明。
- [ ] 每天收尾时更新当天文档的“日终交接”。
## 一周总体目标
- Day 1先把资产、版本、审核、运行日志、审计日志等基础地基建好。
- Day 2把任务规则中心和后端资产体系打通。
- Day 3建立语义本体 MVP让用户问题能变成稳定结构。
- Day 4建立 Orchestrator让请求能被统一路由、审计、降级。
- Day 5建立 User Agent MVP处理用户查询、解释和草稿生成。
- Day 6建立 Hermes MVP处理定时巡检、统计、知识和规则草稿。
- Day 7做加固、测试、演示、验收和下一阶段交接。
## 一周暂不完成
- 完整 OCR 生产识别引擎。
- 完整发票验真 MCP 深度接入。
- 完整 LLM Wiki 向量检索。
- 全量财务域数据打通。
- 规则自动上线。
- 完整 CI/CD 质量门禁。
## 生产底线
- 所有写操作必须有审计日志。
- 所有 Agent 执行必须生成 `run_id`
- 所有规则必须有版本。
- 未审核规则不能上线。
- 高风险动作只能生成草稿或建议,不能自动提交。
- 外部能力失败必须有降级结果。
- 语义解析结果必须可回放。

View File

@@ -1,73 +0,0 @@
# Agent Week Plan 总控
本文件是本周总览和执行索引。
每个 Day 文档现在同时包含:
- 路线图
- 当前完成情况
- 验收门槛
- 详细执行清单
不再跳转独立执行细则目录。
## 快速浏览
- HTML 总览:[agent_week_plan_html/index.html](<../agent_week_plan_html/index.html>)
- Day 1 HTML[agent_week_plan_html/day-1.html](<../agent_week_plan_html/day-1.html>)
## 执行方式
1. 先看本文件,确认今天做哪一天、当前状态和依赖顺序。
2. 再打开当天 daily 文档,直接在同一份文档里推进开发。
3. 完成一个最小 TODO 后,再改成 `[x] ~~...~~`
4. 每天结束时回填阻塞记录、验收结果和日终交接。
## 一周节奏
| Day | 状态 | 主题 | 主要交付 | Markdown | HTML |
| --- | --- | --- | --- | --- | --- |
| Day 1 | 已完成2026-05-11 | 基础模型与工程骨架 | 资产、版本、审核、运行日志、审计日志、基础 API、最小财务数据源 | [Day 1](./day_1_foundation_models.md) | [HTML](<../agent_week_plan_html/day-1.html>) |
| Day 2 | 已完成,待补浏览器走查记录 | 任务规则中心联调 | 规则/技能/MCP/任务列表与详情、Markdown、版本、审核 | [Day 2](./day_2_rule_center_integration.md) | [HTML](<../agent_week_plan_html/day-2.html>) |
| Day 3 | 已完成主体功能,待补评测样本扩充 | 语义本体 MVP | 8 字段语义解析、日志、评测入口、OCR 摘要与最小会话上下文带入 | [Day 3](./day_3_semantic_ontology_mvp.md) | [HTML](<../agent_week_plan_html/day-3.html>) |
| Day 4 | 已完成主干与会话串联,待接通提交/附件持久化链路 | Orchestrator 运行时 | 统一入口、路由、权限、工具调用、报销单写入路由、会话 Trace | [Day 4](./day_4_orchestrator_runtime.md) | [HTML](<../agent_week_plan_html/day-4.html>) |
| Day 5 | 已完成问答主链路、草稿创建/补全与会话上下文,待接通提交状态流转 | User Agent MVP | 用户问答、报销单草稿创建/补全/提交、财务查询、规则解释、附件/OCR 带入 | [Day 5](./day_5_user_agent_mvp.md) | [HTML](<../agent_week_plan_html/day-5.html>) |
| Day 6 | 未开始 | Hermes MVP | 定时任务、风险巡检、日报、知识候选、规则草稿 | [Day 6](./day_6_hermes_mvp.md) | [HTML](<../agent_week_plan_html/day-6.html>) |
| Day 7 | 未开始 | 加固、演示和验收 | 回归、测试、演示脚本、交付说明 | [Day 7](./day_7_hardening_demo_acceptance.md) | [HTML](<../agent_week_plan_html/day-7.html>) |
## 当前完成情况
- Day 1 已完成,后端基础模型、审计和最小财务数据源已可供后续能力复用。
- Day 2 已完成主要前后端联调,当前仅剩浏览器人工走查记录待补。
- Day 3 主体已完成,`/api/v1/ontology/parse`、8 字段返回、缺槽位追问、权限判断和前端调试入口均已落地OCR 摘要、附件上下文和最小会话历史已进入语义层,前端浏览器时间上下文也已接入相对时间换算,当前主要剩叙述型报销、附件/OCR 带入样本和模糊追问样本继续扩充。
- Day 4 主干已完成Orchestrator 已具备统一入口、User Agent / Hermes 路由、权限阻断、ToolCall 记录、Trace、降级和 `conversation_id` 会话串联;`expense_claims` 草稿建单/改单与 ToolCall / Audit 已接通,但提交、附件持久化和更细的 ToolCall Trace 仍未接通。
- Day 5 问答主链路已完成个人工作台和报销对话框已能把文本、附件名称、OCR 摘要、页面上下文和会话 ID 带入 Orchestrator并返回回答、规则引用、风险说明、结构化草稿和识别核对面板核对 UI 已调整为“右侧只看识别结果、主对话负责待补与风险、底部负责动作”,但附件 / OCR 结果落库及 `draft -> submitted` 仍未完成。
## Day 1 - Day 5 未完成补齐清单
- Day 1当前周计划范围内无新增遗留项基础资产、日志、审计和最小财务表已完成文件资产、OCR 结果表和风险事件表作为 Day 5 真落库前置底座,设计已完成但代码未落地。
- Day 2仍缺一轮浏览器人工走查记录需补充规则中心真实页面联调截图或缺陷清单。
- Day 3仍需补充叙述型报销长句样本、附件/OCR 摘要带入样本、模糊短句追问样本,并把这些样本纳入自动评测。
- Day 4仍需接通 `submit_expense_claim` 真服务补齐附件挂接服务注册、ToolCall 更细粒度记录和前端 Trace 展示。
- Day 5仍需把附件和 OCR 识别结果真正落到 `document_assets``document_asset_versions``expense_item_documents``document_ocr_results`,并完成 `draft -> submitted` 状态流转、前端确认动作回写和提交流程确认。
## 关键依赖顺序
1. Day 1 必须先完成,因为后面所有能力都依赖资产、版本、审核、日志。
2. Day 2 必须在 Day 3 前完成,因为语义和 Agent 需要读取规则、技能、MCP、任务资产。
3. Day 3 必须在 Day 4 前完成,因为 Orchestrator 依赖语义本体做路由。
4. Day 4 必须在 Day 5 / Day 6 前完成,因为 User Agent 和 Hermes 都应该由 Orchestrator 调用。
5. Day 5 和 Day 6 可以部分并行但都必须遵守权限、审计、Trace。
6. Day 7 不新增大功能,只做加固、验收和交接。
## 最终验收
- 任务规则中心能看到规则、技能、MCP、任务。
- 规则详情能编辑 Markdown、查看最近 5 个版本、切换版本。
- 未审核规则不能上线。
- 用户问题能解析出语义本体 8 字段。
- Orchestrator 能路由到 User Agent 和 Hermes。
- User Agent 能完成查询、解释、报销单草稿创建、字段补全和提交前确认。
- Hermes 能执行一次风险巡检或日报任务。
- AgentRun、ToolCall、AuditLog 都能追溯。
- 有演示脚本和下一阶段交接文档。

View File

@@ -1,221 +0,0 @@
# Day 1基础模型与工程骨架
## 当前状态
- [x] ~~Day 1 已完成2026-05-11。~~
- [x] ~~后端基础模型、API 骨架、种子数据、审计能力和 Day 2 联调入口均已落地。~~
## 今天的大开发点
Day 1 只做地基,不做复杂 Agent 智能。
核心是把后面 6 天都会用到的基础对象建出来:资产、版本、审核、运行日志、工具调用日志、语义解析日志、审计日志,以及最小财务业务数据来源。
## 为什么第一天做这个
如果没有稳定的数据模型后面的任务规则中心、语义本体、Orchestrator、User Agent、Hermes 都会各自临时造结构,后期会很难合并。
## 今天主要交付
- [x] ~~统一资产模型规则、技能、MCP、任务。~~
- [x] ~~版本模型:规则 Markdown 和其他资产配置快照。~~
- [x] ~~审核模型:未审核不能上线。~~
- [x] ~~Agent 运行日志:所有 Agent 执行都有 `run_id`。~~
- [x] ~~工具调用日志MCP、数据库、LLM、OCR、规则引擎调用都可追踪。~~
- [x] ~~语义解析日志:后续语义本体结果可回放。~~
- [x] ~~审计日志:所有写操作可追责。~~
- [x] ~~最小财务业务数据来源:报销、应收、应付。~~
## 实际落地结果
- [x] ~~新增 `AgentAsset`、`AgentAssetVersion`、`AgentAssetReview`、`AgentRun`、`AgentToolCall`、`SemanticParseLog`、`AuditLog`、`ExpenseClaim`、`ExpenseClaimItem`、`AccountsReceivableRecord`、`AccountsPayableRecord`。~~
- [x] ~~新增 `/api/v1/agent-assets`、`/api/v1/agent-runs`、`/api/v1/audit-logs` 相关接口。~~
- [x] ~~种子数据已覆盖 3 条规则、2 条技能、2 条 MCP、3 条任务,以及报销 / 应收 / 应付示例数据。~~
- [x] ~~旧开发库启动时会自动补齐新增资产和版本,不需要手动清库。~~
相关架构文档:
- [整体架构](<../agent plan/01_overall_architecture.md>)
- [语义本体](<../agent plan/02_semantic_ontology.md>)
- [数据契约与治理](<../agent plan/06_data_contracts_and_governance.md>)
- [能力注册](<../agent plan/07_capability_registry.md>)
- [权限与确认](<../agent plan/08_permission_confirmation.md>)
- [观测与 Trace](<../agent plan/09_observability_and_trace.md>)
- [财务单据标准模型](<../agent plan/14_financial_document_canonical_model.md>)
## 当天验收门槛
- [x] ~~数据库或等价存储能创建基础对象。~~
- [x] ~~API 服务能启动。~~
- [x] ~~资产列表能返回规则、技能、MCP、任务。~~
- [x] ~~规则资产能关联 Markdown 当前版本。~~
- [x] ~~未审核规则不能上线。~~
- [x] ~~AgentRun 能保存一条运行记录。~~
- [x] ~~AuditLog 能保存一条写操作记录。~~
## Day 2 联调入口
- `GET /api/v1/agent-assets`
- `GET /api/v1/agent-assets/{asset_id}`
- `GET /api/v1/agent-assets/{asset_id}/versions?limit=5`
- `POST /api/v1/agent-assets/{asset_id}/reviews`
- `POST /api/v1/agent-assets/{asset_id}/activate`
- `GET /api/v1/audit-logs`
## 今天不做
- 不做完整 Agent 对话。
- 不做完整 Hermes 调度。
- 不做真实 OCR。
- 不做复杂规则推理。
## 详细执行清单
以下内容为合并后的详细执行清单。
## 0. 开始前检查
- [x] ~~确认后端目录为 `/app/server`,模型、路由、启动入口和测试目录已定位。~~
- [x] ~~确认本次改动以增量方式落到现有 FastAPI + SQLAlchemy 工程,不回退无关文件。~~
验收证据:
- [x] ~~模型注册位于 `server/src/app/db/base.py`,路由注册位于 `server/src/app/api/v1/router.py`,启动入口位于 `server/src/app/main.py`,测试位于 `server/tests`。~~
## 1. 统一命名和边界
- [x] ~~统一枚举:`rule | skill | mcp | task`、`draft | review | active | disabled`、`pending | approved | rejected`、`orchestrator | user_agent | hermes`。~~
- [x] ~~统一运行来源、权限级别、内容类型、运行状态和工具类型命名,避免出现第二套并行语义。~~
验收证据:
- [x] ~~`server/src/app/core/agent_enums.py` 已成为模型、Schema 和服务层的统一枚举入口。~~
## 2. 设计最小财务业务数据模型
- [x] ~~建立 `expense_claims`、`expense_claim_items`、`accounts_receivable`、`accounts_payable`。~~
- [x] ~~字段覆盖时间、地点、理由、金额、员工、部门、状态,以及应收 / 应付的金额、到期日、账龄、风险标记。~~
验收证据:
- [x] ~~`server/src/app/models/financial_record.py` 与 `document/development/agent plan/14_financial_document_canonical_model.md` 形成直接映射。~~
## 3. 建立 AgentAsset 模型
- [x] ~~建立 `AgentAsset`,包含 `asset_type`、`code`、`name`、`description`、`domain`、`scenario_json`、`owner`、`reviewer`、`status`、`current_version`、`config_json` 等核心字段。~~
- [x] ~~对 `code`、`asset_type`、`status`、`domain` 建立唯一约束或索引。~~
验收证据:
- [x] ~~资产列表可按 `rule`、`skill`、`mcp`、`task` 四类过滤返回。~~
## 4. 建立 AgentAssetVersion 模型
- [x] ~~建立 `AgentAssetVersion`,规则版本保存 Markdown其余资产版本保存 JSON 快照。~~
- [x] ~~对 `asset_id + version` 建立唯一约束,并支持按资产读取最近版本列表。~~
验收证据:
- [x] ~~规则详情接口可返回 `current_version_content` 和 `recent_versions`。~~
## 5. 建立 AgentAssetReview 模型
- [x] ~~建立 `AgentAssetReview`,保存版本、审核人、审核状态、审核备注和审核时间。~~
- [x] ~~服务层实现规则版本未 `approved` 时禁止上线。~~
验收证据:
- [x] ~~`POST /api/v1/agent-assets/{asset_id}/activate` 对待审规则返回 400 拦截。~~
## 6. 建立 AgentRun 模型
- [x] ~~建立 `AgentRun`,包含 `run_id`、`agent`、`source`、`ontology_json`、`route_json`、`permission_level`、`status`、`result_summary`、`error_message` 等字段。~~
- [x] ~~所有运行记录统一生成 `run_id`,并允许失败态保存错误信息。~~
验收证据:
- [x] ~~`AgentRunService.create_run()` 会自动生成 `run_` 前缀标识,并可回读失败摘要。~~
## 7. 建立 AgentToolCall 模型
- [x] ~~建立 `AgentToolCall`,可记录工具类型、工具名、请求 / 响应 JSON、耗时和错误信息。~~
- [x] ~~同一个 `run_id` 下支持多次工具调用追踪。~~
验收证据:
- [x] ~~种子运行数据已覆盖数据库查询、MCP 调用和权限规则引擎调用。~~
## 8. 建立 SemanticParseLog 模型
- [x] ~~建立 `SemanticParseLog`,覆盖场景、意图、实体、时间范围、指标、约束、风险、权限和置信度。~~
- [x] ~~支持按 `run_id` 回放 Day 3 语义结果。~~
验收证据:
- [x] ~~`GET /api/v1/agent-runs/{run_id}` 已能携带 `semantic_parse` 返回。~~
## 9. 建立 AuditLog 模型
- [x] ~~建立 `AuditLog` 和统一 `AuditLogService`。~~
- [x] ~~资产创建、版本保存、审核、上线等写操作都会留下审计记录。~~
验收证据:
- [x] ~~`GET /api/v1/audit-logs` 可返回种子审计日志,服务层新建资产也会落审计。~~
## 10. 建立 Schema / DTO
- [x] ~~建立 `AgentAssetCreate / Update / Read / ListItem`、`AgentAssetVersionRead`、`AgentAssetReviewRead`、`RuleMarkdownUpdate`、`AgentRunRead`、`AgentToolCallRead`、`SemanticParseRead`。~~
- [x] ~~所有 JSON 字段以结构化对象返回,不回传字符串化 JSON。~~
验收证据:
- [x] ~~列表 DTO 不返回大块 Markdown详情 DTO 返回当前版本正文和最近版本。~~
## 11. 建立 API 骨架
- [x] ~~建立 `GET/POST/PATCH /api/v1/agent-assets`、`GET /api/v1/agent-assets/{asset_id}`、`GET/POST /api/v1/agent-assets/{asset_id}/versions`、`POST /api/v1/agent-assets/{asset_id}/reviews`、`POST /api/v1/agent-assets/{asset_id}/activate`。~~
- [x] ~~建立 `GET /api/v1/agent-runs`、`GET /api/v1/agent-runs/{run_id}`、`GET /api/v1/audit-logs`。~~
验收证据:
- [x] ~~所有接口已挂到 `server/src/app/api/v1/router.py`,并通过 `create_app()` 自动暴露。~~
## 12. 建立种子数据
- [x] ~~种子资产补齐到 3 条规则、2 条技能、2 条 MCP、3 条任务。~~
- [x] ~~三条规则都具备至少 2 个版本,并覆盖 `approved / pending / rejected` 三种审核样本。~~
- [x] ~~旧开发数据库启动时会自动增量补齐新增资产和版本,不要求手动清库。~~
验收证据:
- [x] ~~Smoke`GET /api/v1/agent-assets` 返回 10 条资产,`GET /api/v1/agent-runs` 返回 3 条运行日志,`GET /api/v1/audit-logs` 返回 4 条审计日志。~~
## 13. 最小测试
- [x] ~~新增 Day 1 服务层与接口层测试,覆盖种子完整性、版本历史、未审核不能上线、运行日志生成和审计日志写入。~~
- [x] ~~Ruff 校验通过Day 1 新增文件保持可检查状态。~~
验收证据:
- [x] ~~`/app/server/.venv/bin/pytest -q /app/server/tests/test_agent_asset_service.py /app/server/tests/test_agent_foundation_endpoints.py` -> `11 passed`。~~
- [x] ~~`/app/server/.venv/bin/pytest -q tests` 已通过全量后端测试。~~
## 14. Day 1 验收
- [x] ~~数据库能创建所有新增表或等价结构。~~
- [x] ~~API 服务能启动OpenAPI 能看到新增接口。~~
- [x] ~~资产列表接口返回规则、技能、MCP、任务规则详情带 Markdown 当前版本和最近版本列表。~~
- [x] ~~未审核规则不能上线AgentRun 和 AuditLog 均可保存记录。~~
- [x] ~~所有 Day 1 TODO 已改为完成态。~~
## 阻塞记录
- [x] ~~暂无阻塞。~~
## 日终交接
- [x] ~~已完成模型:资产、版本、审核、运行日志、工具调用、语义解析、审计、报销、应收、应付。~~
- [x] ~~已完成 API`/api/v1/agent-assets`、`/api/v1/agent-runs`、`/api/v1/audit-logs`。~~
- [x] ~~Day 2 前端联调应优先使用 `GET /api/v1/agent-assets`、`GET /api/v1/agent-assets/{asset_id}`、`GET /api/v1/agent-assets/{asset_id}/versions?limit=5`、`POST /api/v1/agent-assets/{asset_id}/reviews`、`POST /api/v1/agent-assets/{asset_id}/activate`。~~
- [x] ~~后续 Day 4 及以后运行时方向按用户要求转向 `LangChain + LangGraph`Hermes 继续作为内部数字员工入口Day 1 保留为数据与治理底座。~~

View File

@@ -1,296 +0,0 @@
# Day 2任务规则中心联调
## 今天的大开发点
把任务规则中心从静态页面改成可和后端资产体系联动的生产形态。
重点是规则、技能、MCP、任务四类资产的列表和详情以及规则 Markdown、版本、审核、上线约束。
## 为什么第二天做这个
任务规则中心是业务人员管理 Agent 能力的入口。后续语义本体、Orchestrator、User Agent、Hermes 都要读取这里注册的规则、技能、MCP 和任务。
## 今天主要交付
- 规则、技能、MCP、任务四个页签对接资产 API。
- 列表支持搜索、筛选、状态展示。
- 规则详情展示 Markdown 内容。
- 管理员可编辑规则 Markdown。
- 规则版本展示最近 5 个版本。
- 版本切换需要弹窗确认。
- 审核者信息放在标题区域。
- 右侧只保留版本信息。
- 未审核规则上线时被后端拦截。
## 当前完成情况
- [x] ~~四个页签已切到真实资产 API。~~
- [x] ~~规则 Markdown、版本切换、审核、上线动作已联调。~~
- [x] ~~前端构建已通过。~~
- [ ] 浏览器手动走查记录待补。
相关架构文档:
- [能力注册](<../agent plan/07_capability_registry.md>)
- [规则形成生命周期](<../agent plan/13_rule_formation_lifecycle.md>)
- [数据契约与治理](<../agent plan/06_data_contracts_and_governance.md>)
## 当天验收门槛
- 四个页签可切换并有真实 API 或 Mock API 数据。
- 规则详情可编辑 Markdown。
- Markdown 保存后刷新不丢失。
- 版本卡片可切换版本。
- 未审核规则不能上线。
- 前端构建通过。
## 今天不做
- 不做规则自动生成。
- 不做完整 MCP 真实调用。
- 不做复杂权限矩阵。
- 不重做 UI 风格,只在现有风格上微调。
## 详细执行清单
以下内容为合并后的详细执行清单。
## 0. 开始前检查
- [x] ~~确认 Day 1 API 已可访问。~~
- [x] ~~确认前端任务规则中心文件位置。~~
- [x] ~~确认现有路由名称和导航名称。~~
- [x] ~~确认现有 UI 风格,不重新做大改版。~~
- [x] ~~确认当前页面已有页签规则、技能、MCP、任务。~~
- [x] ~~确认详情页隐藏顶部 title bar 的逻辑仍然有效。~~
- [x] ~~确认返回列表栏高度没有被重新拉高。~~
## 1. API Client
- [x] ~~新增或扩展资产列表请求函数。~~
- [x] ~~新增资产详情请求函数。~~
- [x] ~~新增版本列表请求函数。~~
- [x] ~~新增规则 Markdown 保存请求函数。~~
- [x] ~~新增审核请求函数。~~
- [x] ~~新增上线请求函数。~~
- [x] ~~新增运行日志请求函数。~~
- [x] ~~给所有请求增加加载态。~~
- [x] ~~给所有请求增加错误态。~~
- [x] ~~给所有写请求增加成功提示。~~
验收证据:
- [x] ~~前端不再只依赖本地硬编码资产数据。~~
- [x] ~~后端不可用时页面有明确错误提示。~~
## 2. 列表页数据接入
- [x] ~~规则页签请求 `asset_type=rule`。~~
- [x] ~~技能页签请求 `asset_type=skill`。~~
- [x] ~~MCP 页签请求 `asset_type=mcp`。~~
- [x] ~~任务页签请求 `asset_type=task`。~~
- [x] ~~搜索框传递关键词或本地过滤。~~
- [x] ~~类型下拉和搜索框可以同时生效。~~
- [x] ~~状态筛选可以过滤 `draft | review | active | disabled`。~~
- [x] ~~列表卡片展示名称。~~
- [x] ~~列表卡片展示摘要。~~
- [x] ~~列表卡片展示状态。~~
- [x] ~~列表卡片展示负责人。~~
- [x] ~~列表卡片展示最近更新时间。~~
- [x] ~~空数据时展示空态。~~
- [x] ~~加载中时展示骨架或加载状态。~~
验收证据:
- [x] ~~四个页签都能切换。~~
- [x] ~~四个页签都有数据或空态。~~
- [x] ~~搜索和筛选不会互相覆盖。~~
## 3. 规则详情页主信息
- [x] ~~打开规则资产时请求详情 API。~~
- [x] ~~Hero title 展示规则名称。~~
- [x] ~~Hero title 下方展示审核者。~~
- [x] ~~Hero title 下方展示审核状态。~~
- [x] ~~Hero title 下方展示上线条件。~~
- [x] ~~Hero title 高度保持紧凑。~~
- [x] ~~详情页不显示外层顶部 title bar。~~
- [x] ~~返回列表栏高度保持原有紧凑高度。~~
验收证据:
- [x] ~~用户能一眼看到该规则是否已审核。~~
- [x] ~~用户不会看到两层 title。~~
## 4. Markdown 编辑器
- [x] ~~从当前版本读取 Markdown 内容。~~
- [x] ~~Markdown 编辑框高度和右侧版本卡片底部对齐。~~
- [x] ~~Markdown 编辑框支持长内容滚动。~~
- [x] ~~Markdown 编辑框保存时调用 API。~~
- [x] ~~保存后创建新版本或更新草稿版本,按后端约定执行。~~
- [x] ~~保存成功后刷新版本列表。~~
- [x] ~~保存失败时保留用户输入。~~
- [x] ~~编辑器禁用态覆盖 `active` 且无编辑权限的情况。~~
- [x] ~~编辑器底部展示最后保存时间。~~
验收证据:
- [x] ~~编辑 Markdown 后刷新页面内容仍存在。~~
- [x] ~~保存失败不会丢内容。~~
- [x] ~~左右卡片底部视觉对齐。~~
## 5. 版本卡片
- [x] ~~右侧只保留版本信息卡片。~~
- [x] ~~版本卡片宽度足够展示版本号、日期、状态。~~
- [x] ~~展示最近 5 个版本。~~
- [x] ~~当前版本有明显但不突兀的标识。~~
- [x] ~~当前版本标识居中显示。~~
- [x] ~~选中状态只变色,不改变内容对齐。~~
- [x] ~~日期列和其他版本日期对齐。~~
- [x] ~~点击非当前版本时弹出确认弹窗。~~
- [x] ~~弹窗展示目标版本号。~~
- [x] ~~弹窗展示切换风险提示。~~
- [x] ~~确认后切换当前展示内容。~~
- [x] ~~取消后不改变当前版本。~~
验收证据:
- [x] ~~版本切换不会造成列表文字位移。~~
- [x] ~~当前版本背景能完全覆盖内容区域。~~
- [x] ~~版本卡片不贴右侧边界。~~
## 6. 审核与上线
- [x] ~~详情中展示审核者姓名。~~
- [x] ~~详情中展示审核时间。~~
- [x] ~~详情中展示审核意见。~~
- [x] ~~未审核规则显示不能上线原因。~~
- [x] ~~点击上线时调用后端上线接口。~~
- [x] ~~后端拒绝时展示拒绝原因。~~
- [x] ~~审核通过后上线按钮可用。~~
- [x] ~~审核动作写入审计日志。~~
- [x] ~~上线动作写入审计日志。~~
验收证据:
- [x] ~~pending 规则无法上线。~~
- [x] ~~approved 规则可以上线。~~
- [x] ~~rejected 规则无法上线。~~
## 7. 技能详情
- [x] ~~技能页签列表展示能力名称。~~
- [x] ~~技能详情展示能力说明。~~
- [x] ~~技能详情展示输入参数。~~
- [x] ~~技能详情展示输出参数。~~
- [x] ~~技能详情展示依赖能力。~~
- [x] ~~技能详情展示适用场景。~~
- [x] ~~技能详情展示负责人。~~
- [x] ~~技能详情展示版本。~~
- [x] ~~技能详情不使用规则 Markdown 编辑器。~~
验收证据:
- [x] ~~技能和规则详情不会混用 UI。~~
## 8. MCP 详情
- [x] ~~MCP 页签列表展示外部服务名称。~~
- [x] ~~MCP 详情展示服务类型。~~
- [x] ~~MCP 详情展示调用地址或能力名。~~
- [x] ~~MCP 详情展示鉴权方式。~~
- [x] ~~MCP 详情展示超时配置。~~
- [x] ~~MCP 详情展示降级策略。~~
- [x] ~~MCP 详情展示最近调用状态。~~
- [x] ~~MCP 详情展示负责人。~~
验收证据:
- [x] ~~MCP 被定义为外部服务,而不是技能规则。~~
## 9. 任务详情
- [x] ~~任务页签展示定时任务名称。~~
- [x] ~~任务详情展示 cron 或调度周期。~~
- [x] ~~任务详情展示执行 Agent默认 Hermes。~~
- [x] ~~任务详情展示任务目标。~~
- [x] ~~任务详情展示风险等级。~~
- [x] ~~任务详情展示最近执行时间。~~
- [x] ~~任务详情展示最近执行结果。~~
- [x] ~~任务详情展示启停状态。~~
验收证据:
- [x] ~~定时任务用户可见名称为“任务”。~~
- [x] ~~技术字段可保留 `schedule`,但 UI 不显示“定时任务”。~~
## 10. 前端质量
- [x] ~~页面在 1366 宽度下无横向滚动。~~
- [x] ~~页面在 1920 宽度下右侧卡片不过宽。~~
- [x] ~~页面在窄屏下详情区域可滚动。~~
- [x] ~~所有按钮有禁用态。~~
- [x] ~~所有弹窗有取消按钮。~~
- [x] ~~所有表单错误有提示。~~
- [x] ~~所有日期格式统一。~~
- [x] ~~状态颜色和现有系统一致。~~
验收证据:
- [x] ~~`npm run build` 通过。~~
- [ ] 任务规则中心手动走查通过。
## 11. Day 2 验收
- [x] ~~规则、技能、MCP、任务四个页签可用。~~
- [x] ~~搜索框和筛选下拉可用。~~
- [x] ~~规则详情展示 Markdown。~~
- [x] ~~规则 Markdown 可保存。~~
- [x] ~~右侧只保留版本信息。~~
- [x] ~~版本可切换且有弹窗确认。~~
- [x] ~~审核者信息在标题下方。~~
- [x] ~~未审核规则不能上线。~~
- [x] ~~前端构建通过。~~
- [x] ~~所有完成项已按完成态标记。~~
## 阻塞记录
- [x] ~~暂无。~~
## 日终交接
- [x] ~~写明已接入的 API。~~
- [x] ~~写明仍然使用 Mock 的字段。~~
- [x] ~~写明 UI 未完成项。~~
- [x] ~~写明 Day 3 语义本体需要复用的资产数据。~~
已接入的 API
- `GET /api/v1/agent-assets?asset_type=rule|skill|mcp|task`
- `GET /api/v1/agent-assets/{asset_id}`
- `GET /api/v1/agent-assets/{asset_id}/versions`
- `POST /api/v1/agent-assets/{asset_id}/versions`
- `POST /api/v1/agent-assets/{asset_id}/reviews`
- `POST /api/v1/agent-assets/{asset_id}/activate`
- `GET /api/v1/agent-runs`
仍然使用 Mock / 种子数据的字段:
- MCP 服务地址仍是 `mock://...` 种子地址,用于占位联调。
- MCP 最近调用状态、任务最近执行结果来自 Day 1 注入的 `AgentRun` 种子数据。
- 技能、MCP、任务详情仍以只读方式展示未开放编辑表单。
UI 未完成项:
- 未做浏览器内人工走查记录,当前仅完成构建验证与代码层联调。
- 技能、MCP、任务的编辑能力仍留待后续 Day 3 / Day 4 之后按权限开放。
Day 3 语义本体需要复用的资产数据:
- 资产主键与编码:`id``code``asset_type`
- 业务归类:`domain``scenario_json`
- 当前生效版本:`current_version``current_version_content``current_version_content_type`
- 治理状态:`status``latest_review``recent_versions`
- 运行关联:`config_json.agent``config_json.cron``AgentRun.task_id``tool_calls`

View File

@@ -1,304 +0,0 @@
# Day 3语义本体 MVP
## 今天的大开发点
建立模型优先的语义解析层,把自然语言问题转换成统一的 8 个核心字段。
这一天的目标不是继续堆关键词,而是先把真实模型接入语义层,让报销、应收、应付、知识和风险相关问题进入稳定结构,再由规则做兜底和校验。
## 为什么第三天做这个
Orchestrator 不能直接根据原始文本做可靠路由。它需要先拿到结构化语义,再决定调用 User Agent、Hermes、规则、MCP 或知识库。
## 今天主要交付
- 语义本体 8 字段结构。
- 场景识别:报销、应收、应付、知识、未知。
- 意图识别:查询、解释、对比、风险检查、草稿、操作。
- 业务对象提取:员工、客户、供应商、部门、项目、单据、金额。
- 时间范围解析。
- 指标和约束解析。
- 风险信号和权限级别判断。
- LLM 结构化解析 Prompt。
- Schema 校验与 JSON 清洗。
- 规则回退解析。
- 低置信度追问和缺槽位追问。
- 语义解析 API。
- 解析日志和最小评测集。
## 当前完成情况
- [x] ~~`/api/v1/ontology/parse` 已上线8 字段语义结构、缺槽位、歧义、权限和澄清问题均可返回。~~
- [x] ~~语义层已切到“模型优先 + 规则回退”,并把结果写入 `AgentRun` / `SemanticParseLog`。~~
- [x] ~~附件名称、附件数量、OCR 摘要和 OCR 文档摘要已能作为上下文带入语义层。~~
- [x] ~~最小会话历史、上一轮场景/意图和 `draft_claim_id` 已能作为上下文带入语义层,用于识别“改成 800”“继续补充”这类追问。~~
- [x] ~~叙述型报销语义已补强:`客户 + 吃饭/请客/宴请/招待` 优先归类为业务招待费,不再误打到应收查询。~~
- [x] ~~相对时间已支持标准化展示:前端会透传浏览器本地时间上下文,`今天 / 昨天 / 本月 / 4 月` 会换算成绝对日期;展示层默认优先显示绝对日期,原始表达仅作为辅助信息。~~
- [x] ~~前端调试入口与核心评测测试已完成并通过。~~
- [ ] 叙述型报销样本、附件/OCR 带入样本和模糊短句追问样本仍需继续扩充。
相关架构文档:
- [语义本体](<../agent plan/02_semantic_ontology.md>)
- [财务单据标准模型](<../agent plan/14_financial_document_canonical_model.md>)
- [数据契约与治理](<../agent plan/06_data_contracts_and_governance.md>)
## 当天验收门槛
- 输入自然语言问题能返回 8 个字段。
- 模型解析失败时能自动回退到规则解析。
- 低置信度问题能返回澄清问题。
- 越权动作不会被标记为可直接执行。
- 解析结果能写入日志。
- 至少覆盖报销、应收、应付三个场景。
- 叙述型报销输入不会被错误路由到应收或应付。
## 今天不做
- 不做复杂多轮对话记忆。
- 不做完整 Agent 自主规划。
- 不做自动执行业务流程。
## 详细执行清单
以下内容为合并后的详细执行清单。
## 0. 开始前检查
- [x] ~~确认 Day 1 的 `SemanticParseLog` 可用。~~
- [x] ~~确认 Day 1 的 `AgentRun` 可用。~~
- [x] ~~确认 Day 2 的资产 API 可用。~~
- [x] ~~找到后端服务层目录。~~
- [x] ~~找到现有 LLM 调用或 Mock 调用方式。~~
- [x] ~~确认当前是否允许真实调用 LLM。~~
- [x] ~~确认当前运行时模型槽位可用于语义解析。~~
- [x] ~~如果真实模型不可用,已准备规则解析回退路径。~~
## 1. 定义 8 个核心字段
- [x] ~~定义字段 `scenario`,表示业务场景。~~
- [x] ~~定义字段 `intent`,表示用户意图。~~
- [x] ~~定义字段 `entities`,表示业务对象。~~
- [x] ~~定义字段 `time_range`,表示时间范围。~~
- [x] ~~定义字段 `metrics`,表示指标或金额口径。~~
- [x] ~~定义字段 `constraints`,表示过滤条件。~~
- [x] ~~定义字段 `risk_flags`,表示风险信号。~~
- [x] ~~定义字段 `permission`,表示动作权限。~~
- [x] ~~为每个字段写清楚类型。~~
- [x] ~~为每个字段写清楚是否必填。~~
- [x] ~~为每个字段写清楚默认值。~~
- [x] ~~为每个字段写清楚示例。~~
验收证据:
- [x] ~~8 个字段在 Schema、服务层、日志中名字一致。~~
## 2. 设计字段枚举
- [x] ~~`scenario` 支持 `expense`。~~
- [x] ~~`scenario` 支持 `accounts_receivable`。~~
- [x] ~~`scenario` 支持 `accounts_payable`。~~
- [x] ~~`scenario` 支持 `knowledge`。~~
- [x] ~~`scenario` 支持 `unknown`。~~
- [x] ~~`intent` 支持 `query`。~~
- [x] ~~`intent` 支持 `explain`。~~
- [x] ~~`intent` 支持 `compare`。~~
- [x] ~~`intent` 支持 `risk_check`。~~
- [x] ~~`intent` 支持 `draft`。~~
- [x] ~~`intent` 支持 `operate`。~~
- [x] ~~`permission.level` 支持 `read`。~~
- [x] ~~`permission.level` 支持 `draft_write`。~~
- [x] ~~`permission.level` 支持 `approval_required`。~~
- [x] ~~`permission.level` 支持 `forbidden`。~~
验收证据:
- [x] ~~未识别的问题不会抛异常,返回 `unknown`。~~
## 3. 建立 Schema
- [x] ~~定义 `OntologyParseRequest`。~~
- [x] ~~`OntologyParseRequest` 包含 `query`。~~
- [x] ~~`OntologyParseRequest` 包含 `user_id`。~~
- [x] ~~`OntologyParseRequest` 包含 `context_json`。~~
- [x] ~~定义 `OntologyParseResult`。~~
- [x] ~~`OntologyParseResult` 包含 8 个核心字段。~~
- [x] ~~`OntologyParseResult` 包含 `confidence`。~~
- [x] ~~`OntologyParseResult` 包含 `clarification_required`。~~
- [x] ~~`OntologyParseResult` 包含 `clarification_question`。~~
- [x] ~~`OntologyParseResult` 包含 `run_id`。~~
- [x] ~~定义字段级错误结构。~~
验收证据:
- [x] ~~OpenAPI 中可以看到语义解析请求和响应。~~
## 4. 实现解析服务
- [x] ~~新增 `SemanticOntologyService` 或同等服务。~~
- [x] ~~实现 `parse(query, user_context)` 主函数。~~
- [x] ~~增加上下文装配层,输入文本、页面上下文、附件摘要和预抽取字段。~~
- [x] ~~实现模型优先的结构化语义解析。~~
- [x] ~~约束模型只输出 JSON。~~
- [x] ~~对模型输出做清洗、提取和 Schema 校验。~~
- [x] ~~模型失败时自动回退到规则解析。~~
- [x] ~~在结果中记录本次使用了 `llm_primary` 还是 `rule_fallback`。~~
- [x] ~~报销关键词映射到 `expense`。~~
- [x] ~~应收、回款、客户欠款映射到 `accounts_receivable`。~~
- [x] ~~应付、供应商、付款映射到 `accounts_payable`。~~
- [x] ~~风险、异常、重复、超标映射到 `risk_check`。~~
- [x] ~~为什么、依据、规则映射到 `explain`。~~
- [x] ~~统计、汇总、多少映射到 `query`。~~
- [x] ~~生成、创建、发起映射到 `draft` 或 `operate`。~~
- [x] ~~无法识别时返回低置信度和澄清问题。~~
- [x] ~~叙述型报销输入优先识别为创建/草稿,而不是查询。~~
验收证据:
- [x] ~~“查一下本周报销超标风险”能识别为 expense + risk_check。~~
- [x] ~~“客户 A 这个月还有多少应收”能识别为 accounts_receivable + query。~~
- [x] ~~“供应商 B 明天要付多少钱”能识别为 accounts_payable + query。~~
- [x] ~~“我今天去客户现场招待了客户花销了1000元”不会错误识别为应收查询。~~
- [x] ~~“昨天请客户吃饭花了 200 元”会优先识别为报销草稿语义,并把“昨天”换算为用户本地日期下的绝对日期。~~
## 5. 解析业务对象
- [x] ~~从问题中提取员工姓名。~~
- [x] ~~从问题中提取部门。~~
- [x] ~~从问题中提取客户。~~
- [x] ~~从问题中提取供应商。~~
- [x] ~~从问题中提取项目。~~
- [x] ~~从问题中提取单据号。~~
- [x] ~~从问题中提取金额。~~
- [x] ~~从问题中提取费用类型。~~
- [x] ~~无法提取时返回空数组,不返回 null。~~
验收证据:
- [x] ~~“张三 4 月差旅报销”能提取员工、月份、费用类型。~~
## 6. 解析时间范围
- [x] ~~支持今天。~~
- [x] ~~支持昨天。~~
- [x] ~~支持本周。~~
- [x] ~~支持上周。~~
- [x] ~~支持本月。~~
- [x] ~~支持上月。~~
- [x] ~~支持本季度。~~
- [x] ~~支持今年。~~
- [x] ~~支持明确日期。~~
- [x] ~~支持日期区间。~~
- [x] ~~解析结果包含 `start_date` 和 `end_date`。~~
- [x] ~~日期使用 ISO 格式。~~
验收证据:
- [x] ~~“本周”能解析为当前周起止日期。~~
- [x] ~~“2026 年 4 月”能解析为 `2026-04-01` 到 `2026-04-30`。~~
## 7. 解析指标与约束
- [x] ~~识别金额指标。~~
- [x] ~~识别数量指标。~~
- [x] ~~识别超标指标。~~
- [x] ~~识别逾期指标。~~
- [x] ~~识别重复报销指标。~~
- [x] ~~识别部门过滤条件。~~
- [x] ~~识别状态过滤条件。~~
- [x] ~~识别金额阈值过滤条件。~~
- [x] ~~识别排序要求。~~
- [x] ~~识别 Top N 要求。~~
验收证据:
- [x] ~~“列出金额最高的 10 笔报销”能识别排序和 Top 10。~~
## 8. 解析风险与权限
- [x] ~~重复报销映射到 `duplicate_expense`。~~
- [x] ~~发票异常映射到 `invoice_anomaly`。~~
- [x] ~~金额超标映射到 `amount_over_limit`。~~
- [x] ~~逾期应收映射到 `ar_overdue`。~~
- [x] ~~逾期应付映射到 `ap_overdue`。~~
- [x] ~~查询类问题权限为 `read`。~~
- [x] ~~生成草稿权限为 `draft_write`。~~
- [x] ~~审批、上线、付款类动作权限为 `approval_required`。~~
- [x] ~~越权动作权限为 `forbidden`。~~
验收证据:
- [x] ~~“帮我直接付款”不能被标为可直接执行。~~
## 9. API 接口
- [x] ~~新增 `POST /api/v1/ontology/parse`。~~
- [x] ~~请求参数包含用户问题。~~
- [x] ~~请求参数包含用户上下文。~~
- [x] ~~响应包含 8 个字段。~~
- [x] ~~响应包含 `run_id`。~~
- [x] ~~响应包含置信度。~~
- [x] ~~响应包含澄清问题。~~
- [x] ~~每次调用写入 `SemanticParseLog`。~~
- [x] ~~每次调用写入 `AgentRun` 或关联已有 `AgentRun`。~~
验收证据:
- [x] ~~连续调用多次都能在日志中查到。~~
## 10. 前端调试入口
- [x] ~~在合适页面增加语义解析调试入口。~~
- [x] ~~输入框支持自然语言问题。~~
- [x] ~~点击解析后调用 API。~~
- [x] ~~展示 8 个字段。~~
- [x] ~~展示 JSON 原始结果。~~
- [x] ~~展示置信度。~~
- [x] ~~展示澄清问题。~~
- [x] ~~展示 `run_id`。~~
- [x] ~~错误时展示错误信息。~~
验收证据:
- [x] ~~产品和开发可以直接在页面验证解析结果。~~
## 11. 评测集
- [x] ~~创建至少 5 条报销问题。~~
- [ ] 创建至少 5 条叙述型报销问题。
- [ ] 创建至少 3 条附件 / OCR 摘要带入的报销问题。
- [x] ~~创建至少 5 条应收问题。~~
- [x] ~~创建至少 5 条应付问题。~~
- [x] ~~创建至少 3 条知识库问题。~~
- [x] ~~创建至少 3 条越权操作问题。~~
- [ ] 创建至少 3 条模糊短句追问问题。
- [x] ~~为每条问题写期望 `scenario`。~~
- [x] ~~为每条问题写期望 `intent`。~~
- [x] ~~为每条问题写期望权限级别。~~
- [x] ~~编写评测脚本或测试。~~
验收证据:
- [x] ~~当前评测样本集已通过,覆盖样本准确率达到当天设定阈值。~~
## 12. Day 3 验收
- [x] ~~语义解析 API 可用。~~
- [x] ~~8 个核心字段完整返回。~~
- [x] ~~解析日志可查询。~~
- [x] ~~低置信度问题有澄清问题。~~
- [x] ~~越权动作不会被标为可执行。~~
- [x] ~~前端调试入口可用。~~
- [x] ~~评测集可运行。~~
- [x] ~~所有完成项已用 `[x] ~~...~~` 标记。~~
## 阻塞记录
- [x] ~~暂无。~~
## 日终交接
- [x] ~~已支持报销 / 应收 / 应付 / 知识 / 风险 / 草稿 / 越权动作等核心场景关键词、实体与权限解析。~~
- [x] ~~语义层已可接收附件名称、附件数量和 OCR 摘要上下文,但这些样本仍需继续扩到评测集。~~
- [x] ~~当前仍需继续扩充的弱样本主要是叙述型报销长句、附件/OCR 带入和模糊短句追问。~~
- [x] ~~Day 4 可直接复用 `scenario / intent / entities / time_range / metrics / constraints / risk_flags / permission / confidence / missing_slots / ambiguity / parse_strategy / clarification_required / clarification_question / run_id`。~~

View File

@@ -1,254 +0,0 @@
# Day 4Orchestrator 运行时
## 今天的大开发点
建立统一调度层。用户请求和系统任务都先进入 Orchestrator由它完成语义解析、权限判断、能力选择、Agent 路由、工具调用记录和失败降级。
## 为什么第四天做这个
没有 OrchestratorUser Agent 和 Hermes 会各自直接调用能力权限、审计、降级、Trace 都会分散。生产系统必须有统一入口。
## 今天主要交付
- Orchestrator 请求和响应结构。
- 用户请求路由到 User Agent。
- 定时任务路由到 Hermes。
- 权限级别判断。
- 语义补槽完成后的报销草稿创建、草稿更新、提交动作路由。
- 高风险动作确认机制。
- 能力注册查询。
- 工具调用封装。
- AgentRun Trace 查询。
- 失败降级返回。
## 当前完成情况
- [x] ~~`/api/v1/orchestrator/run`、统一路由、权限阻断、ToolCall 记录、Trace 和降级结果已经可用。~~
- [x] ~~用户消息已能路由到 User Agent占位 Hermes 任务也能由定时入口触发。~~
- [x] ~~附件名称、页面上下文和 OCR 摘要已能随 Orchestrator 请求透传到语义层和 User Agent。~~
- [x] ~~Orchestrator 已开始向前端返回结构化 `review_payload`,用于右侧预审面板展示识别意图、槽位、票据和分单建议。~~
- [x] ~~`conversation_id`、会话消息历史和 `draft_claim_id` 已接入 Orchestrator会话内追问可继续落到同一张报销草稿。~~
- [x] ~~已新增最近会话恢复与用户级会话清空接口,个人工作台可显式继续旧会话或删除旧会话后新建。~~
- [x] ~~`clarification_required` 的报销请求已改为返回结构化核对结果,而不是只回一句追问文案。~~
- [x] ~~`review_action`、`review_form_values` 已能透传到 User Agent / 报销草稿服务,用于结构化修改后重识别和保存草稿。~~
- [ ] 真实 `expense_claims` 提交链路尚未接通;草稿建单 / 改单已接到真实落库,附件与 OCR 持久化仍未完成。
- [ ] 报销附件持久化服务、OCR 结果落库服务和前端 ToolCall 细粒度 Trace 展示尚未接通。
相关架构文档:
- [Orchestrator 与运行流程](<../agent plan/04_orchestrator_and_runtime_flow.md>)
- [能力注册](<../agent plan/07_capability_registry.md>)
- [权限与确认](<../agent plan/08_permission_confirmation.md>)
- [观测与 Trace](<../agent plan/09_observability_and_trace.md>)
## 当天验收门槛
- Orchestrator API 可用。
- 用户消息能路由到 User Agent 占位实现。
- 定时任务能路由到 Hermes 占位实现。
- forbidden 请求不会调用下游 Agent。
- 每次运行都有 `run_id` 和 Trace。
- 工具调用失败能记录并返回降级结果。
- 叙述型报销输入在满足最小槽位后能进入建单或改单流程。
## 今天不做
- 不做复杂任务编排 DAG。
- 不做多 Agent 协商。
- 不做自动高风险动作。
## 详细执行清单
以下内容为合并后的详细执行清单。
## 0. 开始前检查
- [x] ~~确认 Day 3 `POST /api/v1/ontology/parse` 可用。~~
- [x] ~~确认 `AgentRun` 可创建。~~
- [x] ~~确认 `AgentToolCall` 可创建。~~
- [x] ~~确认资产列表能查询技能、MCP、任务。~~
- [x] ~~确认权限级别枚举已稳定。~~
- [x] ~~找到后端服务层适合放 Orchestrator 的位置。~~
## 1. Orchestrator 输入输出
- [x] ~~定义 `OrchestratorRequest`。~~
- [x] ~~请求包含 `source`。~~
- [x] ~~请求包含 `user_id`。~~
- [x] ~~请求包含 `message`。~~
- [x] ~~请求包含 `task_id`。~~
- [x] ~~请求包含 `context_json`。~~
- [x] ~~定义 `OrchestratorResponse`。~~
- [x] ~~响应包含 `run_id`。~~
- [x] ~~响应包含 `selected_agent`。~~
- [x] ~~响应包含 `route_reason`。~~
- [x] ~~响应包含 `permission_level`。~~
- [x] ~~响应包含 `status`。~~
- [x] ~~响应包含 `result`。~~
- [x] ~~响应包含 `requires_confirmation`。~~
- [x] ~~响应包含 `trace_summary`。~~
验收证据:
- [x] ~~Orchestrator 响应能直接被前端展示。~~
## 2. 建立 Orchestrator 服务
- [x] ~~新增 `OrchestratorService`。~~
- [x] ~~实现 `run(request)` 主入口。~~
- [x] ~~主入口第一步创建 `AgentRun`。~~
- [x] ~~主入口第二步调用语义解析。~~
- [x] ~~主入口第三步执行权限判断。~~
- [x] ~~主入口第四步选择 Agent。~~
- [x] ~~主入口第五步调用目标 Agent 或返回阻断结果。~~
- [x] ~~主入口第六步更新 `AgentRun` 状态。~~
- [x] ~~所有异常都写入 `AgentRun.error_message`。~~
验收证据:
- [x] ~~正常请求状态为 `succeeded`。~~
- [x] ~~被权限拦截请求状态为 `blocked`。~~
- [x] ~~异常请求状态为 `failed`。~~
## 3. 路由规则
- [x] ~~`source=user_message` 默认路由到 User Agent。~~
- [x] ~~`source=schedule` 默认路由到 Hermes。~~
- [x] ~~`intent=risk_check` 且来源为 schedule 时路由到 Hermes。~~
- [x] ~~`intent=query` 且来源为 user_message 时路由到 User Agent。~~
- [x] ~~`intent=explain` 路由到 User Agent。~~
- [x] ~~`intent=draft` 路由到 User Agent并可返回结构化核对结果、草稿结果或草稿更新结果。~~
- [x] ~~`scenario=expense` 且最小建单槽位完整时,允许进入 `create_expense_claim_draft`。~~
- [x] ~~`scenario=expense` 且已有 `claim_id` 或会话内 `draft_claim_id` 时,允许进入 `update_expense_claim_draft`。~~
- [ ] `scenario=expense` 且用户明确确认提交时,允许进入 `submit_expense_claim`
- [x] ~~`permission.level=approval_required` 时设置 `requires_confirmation=true`。~~
- [x] ~~`permission.level=forbidden` 时不调用下游 Agent。~~
- [x] ~~无法识别或信息不足时返回澄清问题。~~
验收证据:
- [x] ~~同一句风险检查,在用户入口和任务入口有不同路由结果。~~
## 4. 权限判断
- [x] ~~新增权限判断服务或函数。~~
- [x] ~~查询类请求返回 `read`。~~
- [x] ~~草稿类请求返回 `draft_write`。~~
- [ ] 报销草稿字段补全、附件挂接返回 `draft_write`
- [ ] 报销单提交返回 `approval_required`,并要求显式用户确认。
- [ ] 审批、上线、付款类请求返回 `approval_required`
- [x] ~~用户无权限时返回 `forbidden`。~~
- [x] ~~高风险动作不允许自动执行。~~
- [x] ~~需要确认的动作返回确认提示。~~
- [x] ~~权限判断结果写入 `AgentRun.permission_level`。~~
验收证据:
- [x] ~~“直接上线规则”不会被自动执行。~~
- [x] ~~“直接付款”不会被自动执行。~~
## 5. 能力注册查询
- [x] ~~从 `AgentAsset` 查询 active 技能。~~
- [x] ~~从 `AgentAsset` 查询 active MCP。~~
- [x] ~~从 `AgentAsset` 查询 active 任务。~~
- [ ] 查询可用的报销单写入服务和附件挂接服务。
- [ ] 查询可用的 OCR 结果持久化服务和票据文件回溯服务。
- [x] ~~过滤 disabled 能力。~~
- [x] ~~过滤未审核 active 条件不满足的规则。~~
- [x] ~~为每次能力选择记录 `route_json`。~~
- [x] ~~找不到能力时返回降级说明。~~
验收证据:
- [x] ~~禁用 MCP 不会被 Orchestrator 调用。~~
## 6. 工具调用封装
- [x] ~~定义统一工具调用接口。~~
- [ ] 工具请求前写入 `AgentToolCall` running 或准备记录。
- [x] ~~工具成功后写入响应和耗时。~~
- [x] ~~工具失败后写入错误。~~
- [ ] 报销草稿更新、提交也按工具调用或等价服务调用记录。
- [x] ~~报销草稿创建按工具调用或等价服务调用记录。~~
- [ ] 附件挂接、OCR 结果落库、票据回溯查询也按工具调用或等价服务调用记录。
- [x] ~~外部 MCP 调用失败时返回降级结果。~~
- [x] ~~数据库查询失败时返回明确错误。~~
- [x] ~~LLM 调用失败时返回可读提示。~~
验收证据:
- [x] ~~每次 Orchestrator 运行至少可以看到 0 到多条工具调用记录。~~
## 7. API 接口
- [x] ~~新增 `POST /api/v1/orchestrator/run`。~~
- [x] ~~请求支持用户消息。~~
- [x] ~~请求支持任务触发。~~
- [x] ~~响应返回 `run_id`。~~
- [x] ~~响应返回路由结果。~~
- [x] ~~响应返回权限结果。~~
- [x] ~~复用 `GET /api/v1/agent-runs/{run_id}` 查看 Trace。~~
- [x] ~~Trace 接口返回语义解析、路由、工具调用、最终结果。~~
- [x] ~~`POST /api/v1/orchestrator/run` 返回的 `result` 已可携带 `review_payload`。~~
验收证据:
- [x] ~~前端或 curl 可以完整看到一次运行链路。~~
## 8. 前端最小 Trace 查看
- [ ] 在合适位置展示最近运行记录。
- [x] ~~点击当前对话结果可查看 `run_id`。~~
- [x] ~~展示 selected_agent。~~
- [x] ~~展示 route_reason。~~
- [x] ~~展示 permission_level。~~
- [ ] 展示工具调用列表。
- [x] ~~展示错误信息。~~
- [ ] 展示耗时。
- [ ] 展示报销写链路中的 claim_id / claim_no / status 变化。
验收证据:
- [x] ~~开发调试时不需要直接查数据库才能理解主要路由结果。~~
## 9. 测试
- [x] ~~测试用户查询路由到 User Agent。~~
- [x] ~~测试定时任务路由到 Hermes。~~
- [x] ~~测试叙述型报销输入可路由到报销建单服务。~~
- [x] ~~测试同一 `conversation_id` 下的追问会继续更新已有报销草稿。~~
- [ ] 测试报销单提交前必须显式确认。
- [x] ~~测试 forbidden 不调用下游 Agent。~~
- [x] ~~测试 approval_required 返回确认。~~
- [x] ~~测试工具失败写入 ToolCall。~~
- [x] ~~测试 Orchestrator 异常写入 AgentRun。~~
验收证据:
- [x] ~~Orchestrator 核心测试通过。~~
## 10. Day 4 验收
- [x] ~~Orchestrator API 可用。~~
- [x] ~~用户请求能路由到 User Agent 占位实现。~~
- [x] ~~定时任务能路由到 Hermes 占位实现。~~
- [x] ~~语义补槽完成后的报销输入能路由到建单动作。~~
- [x] ~~语义补槽完成后的报销输入能路由到改单动作。~~
- [x] ~~权限阻断有效。~~
- [x] ~~运行 Trace 可查询。~~
- [x] ~~工具调用日志可查询。~~
- [x] ~~降级结果可读。~~
- [x] ~~所有完成项已用 `[x] ~~...~~` 标记。~~
## 阻塞记录
- [x] ~~暂无。~~
## 日终交接
- [x] ~~当前路由规则已稳定为:`user_message -> user_agent`、`schedule -> hermes`、`clarification_required -> blocked`。~~
- [x] ~~当前权限判断已稳定为:`read / draft_write / approval_required / forbidden`,高风险动作默认阻断或要求确认。~~
- [x] ~~Day 5 需承接的接口契约已明确Orchestrator 向 User Agent 传入语义结果、能力码、工具结果,并期待返回 `answer / citations / suggested_actions / draft_payload / risk_flags`。~~
- [x] ~~Day 5 当前已扩展接口契约:除 `answer / citations / suggested_actions / draft_payload / risk_flags` 外,还返回 `review_payload` 用于前端预审工作台。~~
- [x] ~~下一步仍需补齐的运行时写链路是附件持久化、OCR 结果落库和提交状态流转。~~

View File

@@ -1,284 +0,0 @@
# Day 5User Agent MVP
## 今天的大开发点
实现面向用户的自建 Agent。它负责用户提问、流程辅助、规则解释、查询结果解释和草稿生成。
User Agent 只能处理用户侧交互,不负责后台定时内循环,也不能自动执行高风险动作。
## 为什么第五天做这个
Day 1 到 Day 4 已经具备资产、语义、路由和日志基础,此时可以把用户自然语言入口接到真实流程上。
## 今天主要交付
- 用户自然语言入口。
- 对话入口透传首句文本、附件名称和页面上下文。
- 语义识别完整后创建报销单草稿。
- 对话补充字段时更新报销主表、明细和附件关联。
- 用户确认后触发报销单提交和状态变更。
- 报销查询和解释。
- 应收查询和解释。
- 应付查询和解释。
- 规则引用解释。
- 风险原因说明。
- 处理意见草稿。
- 知识库读取骨架。
- 低置信度场景的澄清追问。
- 前端问答或操作入口。
## 当前完成情况
- [x] ~~个人工作台、报销对话框和通用聊天入口已经接通真实 Orchestrator / User Agent 问答链路。~~
- [x] ~~回答、规则引用、风险说明、建议动作和结构化 `draft_payload` 已可返回。~~
- [x] ~~报销对话框已接入 OCR 识别接口附件名称、OCR 摘要和页面上下文已能透传到 Orchestrator / User Agent。~~
- [x] ~~右侧工作台已开始展示结构化 `review_payload`,并已收敛为“识别结果专用区”:核心识别摘要、时间换算说明、逐票据识别结果、可能单据类型、建议归属费用和 OCR 置信度。~~
- [x] ~~个人工作台和报销对话框已接入 `conversation_id` / `draft_claim_id`,同一会话内的连续追问不再按全新请求处理。~~
- [x] ~~个人工作台已支持“继续会话 / 新建会话”,并可恢复最近一次用户会话或清空旧会话后重新开始。~~
- [x] ~~报销核对流已切到产品化交互:正文区负责 AI 式核对提示、待补充信息、风险提醒和底部动作区,右侧只承载识别结果与票据识别明细,动作固定为“取消 / 修改识别信息 / 保存草稿或下一步”。~~
- [ ] 真实 `document_assets` / `document_asset_versions` / `expense_item_documents` / `document_ocr_results` 落库,以及 `draft -> submitted` 状态流转尚未完成;`expense_claims` / `expense_claim_items` 草稿已接通真实落库。
相关架构文档:
- [Agent 职责边界](<../agent plan/03_agent_responsibilities.md>)
- [Orchestrator 与运行流程](<../agent plan/04_orchestrator_and_runtime_flow.md>)
- [LLM Wiki 知识库架构](<../agent plan/12_llm_wiki_knowledge_architecture.md>)
- [规则形成生命周期](<../agent plan/13_rule_formation_lifecycle.md>)
## 当天验收门槛
- 用户能输入自然语言问题。
- 请求必须经过 Orchestrator。
- 至少 3 类财务问题有可读回答。
- 叙述型报销输入在最小槽位满足后能创建 `expense_claims` 草稿。
- 用户确认提交后可把报销单从 `draft` 变更为 `submitted`
- 回答能引用规则或知识。
- 语义低置信度时不会答非所问,而是追问。
- 高风险动作只生成草稿或建议。
- AgentRun Trace 能看到 User Agent 步骤。
## 今天不做
- 不做自动审批。
- 不做自动付款。
- 不做自动上线规则。
- 不做完整知识库检索优化。
- 不假装已读懂未解析的附件内容。
## 详细执行清单
以下内容为合并后的详细执行清单。
## 0. 开始前检查
- [x] ~~确认 Orchestrator 能把用户请求路由到 User Agent。~~
- [x] ~~确认语义本体 8 字段可用。~~
- [x] ~~确认语义层已接入真实模型,而不是仅靠关键词规则。~~
- [x] ~~确认规则资产可查询。~~
- [x] ~~确认 AgentRun 和 ToolCall 可记录。~~
- [x] ~~确认已有现成对话 UI 可复用。~~
- [x] ~~确认财务业务数据已可通过最小真实数据查询。~~
- [x] ~~当前无需额外补最小 Mock 数据服务。~~
## 1. User Agent 输入输出
- [x] ~~定义 `UserAgentRequest`。~~
- [x] ~~请求包含 `run_id`。~~
- [x] ~~请求包含 `user_id`。~~
- [x] ~~请求包含 `message`。~~
- [x] ~~请求包含 `ontology`。~~
- [x] ~~请求包含 `context_json`。~~
- [x] ~~定义 `UserAgentResponse`。~~
- [x] ~~响应包含 `answer`。~~
- [x] ~~响应包含 `citations`。~~
- [x] ~~响应包含 `suggested_actions`。~~
- [x] ~~响应包含 `draft_payload`。~~
- [x] ~~响应包含 `risk_flags`。~~
- [x] ~~响应包含 `requires_confirmation`。~~
验收证据:
- [x] ~~User Agent 响应结构能被 Orchestrator 直接包装返回。~~
## 2. 查询处理
- [x] ~~实现报销查询处理器。~~
- [x] ~~实现应收查询处理器。~~
- [x] ~~实现应付查询处理器。~~
- [ ] 查询前检查权限级别。
- [x] ~~查询时记录 ToolCall。~~
- [x] ~~查询失败时返回可读错误。~~
- [x] ~~查询为空时返回空态解释。~~
- [ ] 查询结果限制返回条数,避免一次返回过大。
验收证据:
- [x] ~~“查本周报销金额”有可读回答。~~
- [x] ~~“客户 A 本月应收多少”有可读回答。~~
- [x] ~~“供应商 B 待付款多少”有可读回答。~~
## 3. 规则解释
- [x] ~~根据语义场景查询相关规则资产。~~
- [x] ~~只引用 active 规则。~~
- [x] ~~读取规则当前版本 Markdown。~~
- [x] ~~从 Markdown 中提取规则摘要。~~
- [x] ~~回答中说明使用了哪些规则。~~
- [x] ~~回答中包含规则版本号。~~
- [x] ~~回答中包含规则更新时间。~~
- [x] ~~没有相关规则时说明缺失。~~
验收证据:
- [x] ~~“为什么这笔报销有风险”能引用规则。~~
## 4. 风险解释
- [x] ~~识别重复报销风险。~~
- [x] ~~识别金额超标风险。~~
- [x] ~~识别发票异常风险。~~
- [x] ~~识别逾期应收风险。~~
- [x] ~~识别逾期应付风险。~~
- [x] ~~风险回答包含风险类型。~~
- [x] ~~风险回答包含触发原因。~~
- [x] ~~风险回答包含建议处理动作。~~
- [x] ~~高风险建议不能变成自动执行。~~
验收证据:
- [x] ~~风险解释结果不是单纯“有风险”,而是有依据。~~
## 5. 草稿生成与单据落库
- [x] ~~支持根据语义结果创建 `expense_claims` 草稿。~~
- [x] ~~报销草稿初始状态写为 `draft`。~~
- [x] ~~支持根据语义结果创建或更新 `expense_claim_items`。~~
- [ ] 支持把用户上传附件挂到 `document_assets``document_asset_versions``expense_item_documents`
- [ ] 支持把 OCR 识别快照写入 `document_ocr_results`,并保留 `ocr_engine``ocr_model``raw_json``confidence`
- [x] ~~对话中补充金额、发生时间、费用类型等已落地字段后,能回写已有草稿而不是只更新内存结果。~~
- [x] ~~支持生成报销处理意见草稿。~~
- [x] ~~支持生成应收催收建议草稿。~~
- [x] ~~支持生成应付付款建议草稿。~~
- [ ] 用户明确确认“提交报销”后,把 `expense_claims.status``draft` 更新为 `submitted`
- [ ] 报销提交时写入 `submitted_at`
- [ ] 报销状态变更写入审计日志。
- [ ] 报销状态变更写入 AgentRun 结果。
- [x] ~~草稿中标明“待人工确认”。~~
- [x] ~~草稿不直接提交业务系统。~~
- [x] ~~草稿生成写入审计日志。~~
- [x] ~~草稿生成写入 AgentRun 结果。~~
- [ ] 草稿创建或更新后向前端返回 `attachment_ids`
- [x] ~~草稿创建或更新后向前端返回 `claim_id`、`claim_no`、`status`。~~
验收证据:
- [ ] “我今天去客户现场招待了客户花销了1000元”在补齐必要字段后可创建报销草稿。
- [ ] “帮我提交这笔报销”在确认后只把状态改到 `submitted`,不会直接改成 `approved``paid`
- [x] ~~“帮我生成处理意见”只返回草稿,不执行审批。~~
## 6. 知识库读取骨架
- [ ] 建立知识条目查询接口或服务。
- [ ] 支持按关键词查询知识条目。
- [ ] 支持按业务场景查询知识条目。
- [ ] User Agent 回答可以引用知识条目。
- [ ] 引用中包含知识标题。
- [ ] 引用中包含更新时间。
- [ ] 知识库不可用时返回降级说明。
验收证据:
- [ ] 知识库失败不会导致整个回答失败。
## 7. 对话或操作入口
- [x] ~~前端增加用户问题输入框。~~
- [x] ~~输入框支持回车或按钮提交。~~
- [x] ~~提交时调用 Orchestrator而不是绕过 Orchestrator。~~
- [x] ~~提交时透传首句文本。~~
- [x] ~~提交时透传附件名称。~~
- [x] ~~提交时透传 OCR 摘要。~~
- [x] ~~提交时透传页面上下文。~~
- [x] ~~提交时透传 `conversation_id` 与 `draft_claim_id`。~~
- [ ] 提交时透传附件 ID。
- [x] ~~展示 Agent 回答。~~
- [x] ~~展示引用规则或知识。~~
- [x] ~~展示建议动作。~~
- [x] ~~展示识别意图摘要、待确认字段和确认动作卡片。~~
- [x] ~~正文区改为简洁核对提示,不再堆叠调度结果或运行明细。~~
- [x] ~~正文区待补充信息和风险提示已改为紧凑高亮样式,避免出现大段冗长说明。~~
- [x] ~~展示逐票据 OCR 识别结果,并支持按 1、2、3… 顺序查看。~~
- [x] ~~右侧逐票据结果已补充“可能单据类型 / 建议归属费用 / 识别置信度”等识别信息。~~
- [x] ~~展示多场景票据的分单建议。~~
- [ ] 展示报销草稿 ID 或 claim_no。
- [ ] 展示当前报销状态。
- [x] ~~展示需要人工确认的提示。~~
- [x] ~~展示 `run_id`。~~
- [x] ~~展示加载态。~~
- [x] ~~展示错误态。~~
验收证据:
- [x] ~~用户可在页面完成一次问答闭环。~~
## 8. 安全边界
- [x] ~~User Agent 不直接修改规则状态。~~
- [x] ~~User Agent 不直接上线规则。~~
- [x] ~~User Agent 不直接审批报销。~~
- [x] ~~User Agent 不直接把报销单改为 `approved` 或 `paid`。~~
- [x] ~~User Agent 不直接付款。~~
- [x] ~~User Agent 不直接删除知识。~~
- [x] ~~所有高风险动作只返回建议或草稿。~~
- [ ] 报销从 `draft` 变更到 `submitted` 之前必须有用户确认。
- [ ] 所有草稿动作标记 `requires_confirmation=true`
- [x] ~~语义低置信度时优先追问,不返回答非所问的查询结果。~~
- [x] ~~没有 OCR/VLM 结果时,不假装读懂图片或票据内容。~~
验收证据:
- [x] ~~提示词要求“直接付款”时仍被阻断。~~
## 9. 测试
- [x] ~~测试报销查询。~~
- [x] ~~测试应收查询。~~
- [ ] 测试应付查询。
- [ ] 测试规则解释。
- [x] ~~测试风险解释。~~
- [ ] 测试 OCR 摘要透传后User Agent 能在回答中正确引用附件语境而不编造内容。
- [x] ~~测试报销草稿创建。~~
- [x] ~~测试报销草稿补槽更新。~~
- [ ] 测试报销状态从 `draft` 变更到 `submitted`
- [x] ~~测试草稿生成。~~
- [ ] 测试越权动作阻断。
- [ ] 测试知识库降级。
验收证据:
- [x] ~~User Agent 核心测试通过。~~
## 10. Day 5 验收
- [x] ~~User Agent 服务可被 Orchestrator 调用。~~
- [x] ~~用户入口可提交自然语言问题。~~
- [x] ~~至少 3 个财务场景有回答。~~
- [x] ~~语义识别完整后的报销输入能创建报销草稿。~~
- [ ] 用户确认后能提交报销并更新状态。
- [x] ~~回答能引用规则或知识。~~
- [x] ~~高风险动作不会自动执行。~~
- [x] ~~AgentRun Trace 能看到 User Agent 步骤。~~
- [x] ~~前端构建通过。~~
- [x] ~~所有完成项已用 `[x] ~~...~~` 标记。~~
## 阻塞记录
- [x] ~~暂无。~~
## 日终交接
- [x] ~~当前已支持报销 / 应收 / 应付查询、规则解释、风险解释、草稿建议与澄清追问。~~
- [x] ~~当前已支持附件名称、OCR 摘要和页面上下文进入对话链路,但这还不是附件真实持久化。~~
- [x] ~~当前已把用户一句话和多票据输入转成结构化预审面板,开始支持字段确认、票据核对和分单建议,而不再只是返回一段文本。~~
- [x] ~~当前仍是占位的主要能力是报销单真实落库、附件持久化、OCR 结果入表和知识库读取,不再是简单静态问答 Mock。~~
- [x] ~~Day 6 Hermes 可直接复用当前的规则检查、风险标签和 Orchestrator Trace / ToolCall 契约。~~

View File

@@ -1,343 +0,0 @@
# Day 6Hermes MVP
## 今天的大开发点
实现 Hermes 数字员工的最小闭环。Hermes 负责后台内循环:定时巡检、统计日报、风险预警、知识维护、规则草稿形成。
## 为什么第六天做这个
Hermes 依赖前几天已经建立的资产、规则、语义、Orchestrator、Trace 和权限体系。放在第六天做,可以避免它变成孤立脚本。
## 今天主要交付
- 任务资产调度入口。
- 手动触发任务 API。
- 系统 Hermes 后台执行入口。
- 每日风险巡检。
- 每日报销、报账、账款统计。
- OCR Mock 接入点。
- 知识候选条目生成。
- 规则草稿生成。
- LLM Wiki 解析目录与增量重建机制。
- Hermes 运行结果展示。
相关架构文档:
- [Agent 职责边界](<../agent plan/03_agent_responsibilities.md>)
- [OCR 票据识别架构](<../agent plan/11_ocr_invoice_architecture.md>)
- [LLM Wiki 知识库架构](<../agent plan/12_llm_wiki_knowledge_architecture.md>)
- [反馈学习闭环](<../agent plan/15_feedback_learning_loop.md>)
## 当天验收门槛
- 至少一个 Hermes 任务可以手动触发。
- 风险巡检有结构化结果。
- 每日统计有结构化结果。
- OCR Mock 调用能记录 ToolCall。
- 知识候选只能是草稿。
- 规则草稿只能是 draft不能自动上线。
## 今天不做
- 不做完整生产调度集群。
- 不做真实 OCR 深度集成。
- 不做自动发布知识。
- 不做自动上线规则。
- 不做每天无差别全量重建 LLM Wiki。
## 本次新增约束
### 1. Hermes 必须是系统后台 Hermes
这次 Hermes 不应继续只是代码里的占位逻辑。
最小可接受形态:
- 后端任务入口能明确区分 `selected_agent=hermes`
- 后端可调用系统安装的 Hermes CLI 或受控 Hermes 进程。
- 即使当前阶段仍允许 Python 内部 fallback也必须保留真实 Hermes 进程接入点。
- Hermes 的模型配置继续由系统设置同步,不允许在任务代码里再写一套模型配置。
- Hermes 执行应记录 `run_id`、ToolCall、错误信息和最终摘要。
### 2. LLM Wiki 必须有独立解析目录
原始知识文件与解析产物必须分离。
推荐目录:
```text
/app/server/storage/knowledge/报销制度 原始制度文件
/app/server/storage/knowledge/.llm_wiki 解析产物根目录
/app/server/storage/knowledge/.llm_wiki/documents/<document_id>/
document.json
text.md
chunks.json
clauses.json
knowledge_candidates.json
rule_candidates.json
/app/server/storage/knowledge/.llm_wiki/index.json
/app/server/storage/knowledge/.llm_wiki/sync_runs.json
```
### 3. LLM Wiki 只能增量形成
不允许每天无脑全量重建。
文档级重建触发条件至少包括:
- 文件名 `original_name` 变更。
- 文件对象 `stored_name` 变更。
- 内容摘要 `sha256` 变更。
- 上传版本 `version_number` 变更。
- 更新时间 `updated_at` 变更,视为人工改动。
如果以上条件都未变化:
- 本次文档应标记为 `unchanged_skipped`
- 不重新抽取文本。
- 不重新生成知识候选。
- 不重新生成规则草稿。
### 4. 规则草稿必须模板化
Hermes 不允许自由生成任意结构的规则。
必须满足:
- 规则 Markdown 使用固定模板。
- 可执行规则 JSON 使用固定模板族,不允许随意拼字段。
- 规则中心要同时展示人类可读的 Markdown 和机器可执行的 JSON。
- Hermes 生成的规则默认 `draft`
- 审核通过前不能 `active`
- Hermes 不能直接覆盖线上 active 规则。
## 详细执行清单
以下内容为合并后的详细执行清单。
## 本轮追加范围2026-05-15
本轮不扩散到新的业务能力,先把已经落地的 LLM Wiki 归纳链路收紧成可运维、可追踪、可持续运行的形态。
本轮目标:
- 把知识管理中的 Hermes 归纳从同步请求改成后台异步任务。
- 用户关闭或切走页面后,归纳任务仍继续执行,不因前端页面生命周期被误判失败。
- 归纳过程中的状态、进度、摘要、异常统一写入 `AgentRun.route_json``result_summary`
- 知识管理页轮询真实任务状态,任务完成后立刻把文档状态从“正归纳”切到最终状态。
- 右侧侧边栏新增“日志管理”入口。
- 日志管理页拆成两类日志:
- Hermes 调用日志查看归纳任务运行状态、当前阶段、文档进度、ToolCall、错误信息。
- 系统运行日志:直接查看 `server/logs` 下的系统日志文本。
本轮边界:
- 仍然使用系统 Hermes CLI 入口,不虚构不存在的 gateway 推理接口。
- 不引入完整消息队列或 Celery 集群,先用后端受控后台任务管理器落地。
- 不把日志页做成审计替代品,重点只覆盖 Hermes 运行日志和系统运行日志。
- 不把普通用户开放为日志管理员,日志查看仍属于管理员能力。
## 0. 开始前检查
- [x] ~~确认任务资产 `asset_type=task` 可查询。~~
- [x] ~~确认 Orchestrator 能处理 `source=schedule`。~~
- [x] ~~确认系统 Hermes CLI 或等价后台 Hermes 进程可被调用。~~
- [x] ~~确认 AgentRun 和 ToolCall 可记录。~~
- [x] ~~确认是否已有后台任务框架。~~
- [ ] 如果没有后台任务框架,先用手动触发 API 模拟定时执行。
## 1. Hermes 输入输出
- [ ] 定义 `HermesTaskRequest`
- [ ] 请求包含 `run_id`
- [ ] 请求包含 `task_asset_id`
- [ ] 请求包含 `task_type`
- [ ] 请求包含 `schedule_time`
- [ ] 请求包含 `context_json`
- [ ] 定义 `HermesTaskResult`
- [ ] 响应包含 `summary`
- [ ] 响应包含 `risk_items`
- [ ] 响应包含 `statistics`
- [ ] 响应包含 `knowledge_updates`
- [ ] 响应包含 `draft_rules`
- [ ] 响应包含 `next_actions`
验收证据:
- [ ] Hermes 响应能被任务详情或运行日志展示。
## 2. 任务调度入口
- [x] ~~新增手动触发任务 API。~~
- [x] ~~API 参数支持任务资产 ID。~~
- [x] ~~API 调用 Orchestratorsource 为 `schedule`。~~
- [x] ~~Orchestrator 路由到 Hermes。~~
- [x] ~~Hermes 执行结果写入 AgentRun。~~
- [ ] 任务执行失败时写入错误。
- [ ] 任务执行结束后更新任务最近执行时间。
- [ ] 任务执行结束后更新任务最近执行状态。
- [x] ~~保留真实 Hermes 进程执行入口,不把 Hermes 固定写死为本地占位函数。~~
验收证据:
- [x] ~~可以手动触发一次 Hermes 任务并看到运行结果。~~
## 3. 每日风险巡检
- [ ] 实现重复报销巡检。
- [ ] 实现金额超标巡检。
- [ ] 实现发票异常巡检占位。
- [ ] 实现应收逾期巡检。
- [ ] 实现应付异常付款巡检。
- [ ] 每个风险项包含风险类型。
- [ ] 每个风险项包含业务对象。
- [ ] 每个风险项包含触发规则。
- [ ] 每个风险项包含建议动作。
- [ ] 每个风险项包含风险等级。
验收证据:
- [ ] 风险巡检结果可以被用户理解和追溯。
## 4. 每日统计
- [ ] 统计当日报销单数量。
- [ ] 统计当日报销金额。
- [ ] 统计当日报账数量。
- [ ] 统计当日报账金额。
- [ ] 统计应收新增金额。
- [ ] 统计应收逾期金额。
- [ ] 统计应付待付金额。
- [ ] 统计应付逾期金额。
- [ ] 输出日报摘要。
验收证据:
- [ ] Hermes 能生成一份每日财务摘要。
## 5. OCR 接入点
- [ ] 原始票据先落 `document_assets``document_asset_versions`,不直接以内存临时文件参与流程。
- [ ] 建立 OCR 识别服务接口。
- [ ] 定义发票识别输入结构。
- [ ] 定义发票识别输出结构。
- [ ] 输出结构包含发票号。
- [ ] 输出结构包含开票日期。
- [ ] 输出结构包含金额。
- [ ] 输出结构包含税额。
- [ ] 输出结构包含销售方。
- [ ] 输出结构包含购买方。
- [ ] 输出结构包含置信度。
- [ ] OCR 输入可通过 `storage_key` 或等价文件定位字段读取原件。
- [ ] 当前阶段允许使用 Mock 结果。
- [ ] OCR 调用写入 ToolCall。
验收证据:
- [ ] Hermes 风险巡检中可以调用 OCR Mock。
## 6. 知识库维护
- [ ] 建立知识条目写入服务。
- [x] ~~建立 `.llm_wiki` 独立解析目录。~~
- [x] ~~原始文档与解析产物物理隔离。~~
- [x] ~~文本抽取结果落 `text.md`。~~
- [x] ~~分块结果落 `chunks.json`。~~
- [x] ~~文档索引落 `index.json`。~~
- [x] ~~同步记录落 `sync_runs.json`。~~
- [x] ~~文档签名包含 `original_name`、`stored_name`、`sha256`、`version_number`、`updated_at`。~~
- [x] ~~未变化文档跳过重建并记录 `unchanged_skipped`。~~
- [x] ~~Hermes 可以生成知识候选条目。~~
- [x] ~~候选条目包含标题。~~
- [x] ~~候选条目包含正文。~~
- [x] ~~候选条目包含来源。~~
- [x] ~~候选条目包含适用场景。~~
- [x] ~~候选条目默认状态为 `draft`。~~
- [x] ~~知识条目不能自动发布。~~
- [ ] 知识条目写入审计日志。
验收证据:
- [x] ~~Hermes 可以生成待审核知识条目。~~
## 7. 规则草稿形成
- [ ] Hermes 可以根据风险巡检结果生成规则草稿。
- [x] ~~规则草稿使用固定 Markdown 模板。~~
- [x] ~~规则草稿生成可执行 JSON 草稿。~~
- [x] ~~规则中心展示 Markdown + JSON 双视图。~~
- [x] ~~JSON 草稿字段受模板约束,不允许自由扩展。~~
- [x] ~~规则草稿保存为 `asset_type=rule`。~~
- [x] ~~规则草稿状态为 `draft`。~~
- [x] ~~规则草稿包含 Markdown 内容。~~
- [x] ~~规则草稿包含 JSON 内容或等价 `runtime_rule` 配置。~~
- [ ] 规则草稿包含生成原因。
- [ ] 规则草稿包含关联风险样例。
- [x] ~~规则草稿不能自动上线。~~
- [x] ~~规则草稿需要审核人。~~
- [x] ~~规则草稿写入审计日志。~~
- [x] ~~Hermes 不直接覆盖线上 active 规则。~~
验收证据:
- [x] ~~Hermes 生成的新规则出现在规则列表中,但不是 active。~~
## 8. Hermes 页面或日志展示
- [x] ~~任务详情能看到最近执行结果。~~
- [ ] 任务详情能手动触发执行。
- [ ] 任务详情能看到风险项数量。
- [ ] 任务详情能看到日报摘要。
- [ ] 任务详情能看到知识候选数量。
- [ ] 任务详情能看到规则草稿数量。
- [ ] 运行 Trace 能看到 Hermes 步骤。
- [x] ~~错误时展示错误原因。~~
- [ ] 日志管理页能查看 Hermes 归纳任务的实时状态。
- [ ] 日志管理页能查看 Hermes ToolCall 请求与结果。
- [ ] 日志管理页能查看系统运行日志文本。
- [ ] 知识管理页能在后台任务完成后自动刷新归纳状态。
验收证据:
- [x] ~~不查数据库也能判断 Hermes 是否执行成功。~~
## 9. 测试
- [x] ~~测试手动触发任务。~~
- [x] ~~测试 Orchestrator 路由到 Hermes。~~
- [ ] 测试风险巡检输出。
- [ ] 测试日报统计输出。
- [ ] 测试 OCR Mock 调用。
- [x] ~~测试知识候选写入。~~
- [x] ~~测试规则草稿生成。~~
- [ ] 测试 Hermes 异常写入 AgentRun。
- [ ] 测试知识归纳异步任务在接口返回后仍能继续执行。
- [ ] 测试归纳进度能持续写入 AgentRun。
- [ ] 测试系统日志读取接口。
验收证据:
- [ ] Hermes 核心测试通过。
## 10. Day 6 验收
- [x] ~~Hermes 可被 Orchestrator 调用。~~
- [x] ~~至少一个任务可以手动触发。~~
- [ ] 风险巡检有结构化结果。
- [ ] 每日统计有结构化结果。
- [ ] OCR Mock 接入点可用。
- [x] ~~知识候选可生成。~~
- [x] ~~规则草稿可生成且不能自动上线。~~
- [x] ~~任务详情或运行日志能展示结果。~~
- [x] ~~所有完成项已用 `[x] ~~...~~` 标记。~~
## 阻塞记录
- [ ] 暂无。
## 日终交接
- [ ] 写明 Hermes 已支持任务类型。
- [ ] 写明 OCR 当前是真实还是 Mock。
- [ ] 写明生成的知识和规则草稿状态。
- [ ] 写明 Day 7 需要重点回归的路径。

View File

@@ -1,260 +0,0 @@
# Day 7加固、演示和验收
## 今天的大开发点
不再大规模扩功能,集中做回归、加固、测试、演示脚本、文档收尾和下一阶段交接。
## 为什么第七天做这个
一周开发不能只停留在“代码写了”。必须能演示、能追溯、能说清楚边界、能交给下一阶段继续开发。
## 今天主要交付
- 核心链路回归。
- 权限和风险边界复查。
- 审计日志补齐。
- AgentRun Trace 补齐。
- 前端体验修补。
- 测试和构建记录。
- 评测集执行记录。
- 演示数据准备。
- 演示脚本。
- 下一阶段开发建议。
相关架构文档:
- [Agent Plan 总览](<../agent plan/00_README.md>)
- [开发路线图](<../agent plan/05_development_roadmap.md>)
- [观测与 Trace](<../agent plan/09_observability_and_trace.md>)
- [评测与测试集](<../agent plan/10_evaluation_and_testset.md>)
## 当天验收门槛
- 任务规则中心核心路径可演示。
- 语义本体、Orchestrator、User Agent、Hermes 都能跑通最小链路。
- 未审核规则、高风险动作、自动付款等边界都被拦截。
- AgentRun、ToolCall、AuditLog 可追溯。
- 有测试记录、演示脚本和交接说明。
## 今天不做
- 不做新大功能。
- 不临时扩大范围。
- 不绕过测试和验收。
## 详细执行清单
以下内容为合并后的详细执行清单。
## 0. 开始前检查
- [ ] 汇总 Day 1 未完成项。
- [ ] 汇总 Day 2 未完成项。
- [ ] 汇总 Day 3 未完成项。
- [ ] 汇总 Day 4 未完成项。
- [ ] 汇总 Day 5 未完成项。
- [ ] 汇总 Day 6 未完成项。
- [ ] 标记必须今天修复的问题。
- [ ] 标记可以进入下一阶段的问题。
- [ ] 冻结新增需求,只处理验收相关问题。
## 1. 核心链路回归
- [ ] 回归资产列表接口。
- [ ] 回归规则详情接口。
- [ ] 回归 Markdown 保存。
- [ ] 回归版本列表。
- [ ] 回归版本切换。
- [ ] 回归审核接口。
- [ ] 回归上线拦截。
- [ ] 回归语义解析接口。
- [ ] 回归 Orchestrator 路由。
- [ ] 回归 User Agent 问答。
- [ ] 回归 Hermes 任务执行。
- [ ] 回归 AgentRun Trace。
- [ ] 回归 ToolCall 日志。
- [ ] 回归 AuditLog 日志。
验收证据:
- [ ] 从前端能完成至少一条端到端演示路径。
## 2. 权限和风险边界
- [ ] 未审核规则不能上线。
- [ ] rejected 规则不能上线。
- [ ] disabled 能力不能被调用。
- [ ] 用户请求付款必须拦截。
- [ ] 用户请求审批必须需要确认。
- [ ] Hermes 生成规则只能是 draft。
- [ ] Hermes 生成知识只能是 draft。
- [ ] User Agent 生成处理意见只能是草稿。
- [ ] 所有高风险动作响应中包含 `requires_confirmation`
验收证据:
- [ ] 不存在 MVP 期间绕过人工审核的路径。
## 3. 审计和 Trace 补齐
- [ ] 规则保存写 AuditLog。
- [ ] 规则审核写 AuditLog。
- [ ] 规则上线写 AuditLog。
- [ ] Hermes 生成规则草稿写 AuditLog。
- [ ] Hermes 生成知识候选写 AuditLog。
- [ ] User Agent 草稿生成写 AuditLog。
- [ ] Orchestrator 每次运行有 AgentRun。
- [ ] 每次工具调用有 ToolCall。
- [ ] Trace 页面或接口能串起 run_id。
- [ ] 错误 Trace 包含 error_message。
验收证据:
- [ ] 任意一条演示链路都能追溯到 run_id。
## 4. 前端体验修补
- [ ] 任务规则中心列表无明显错位。
- [ ] 详情页无双 title。
- [ ] Hero title 高度紧凑。
- [ ] 返回列表栏高度正常。
- [ ] Markdown 编辑器和版本卡片底部对齐。
- [ ] 版本卡片不贴右侧。
- [ ] 当前版本标识不突兀。
- [ ] 日期列对齐。
- [ ] 弹窗文案清楚。
- [ ] 加载态可见。
- [ ] 错误态可见。
- [ ] 空态可见。
- [ ] 按钮禁用态可见。
- [ ] 窄屏不出现内容重叠。
验收证据:
- [ ] 任务规则中心可以给业务用户演示,不需要解释 UI 异常。
## 5. 测试补齐
- [ ] 运行后端现有测试。
- [ ] 运行新增模型测试。
- [ ] 运行新增 API 测试。
- [ ] 运行语义解析测试。
- [ ] 运行 Orchestrator 测试。
- [ ] 运行 User Agent 测试。
- [ ] 运行 Hermes 测试。
- [ ] 运行前端构建。
- [ ] 如果有前端测试,运行前端测试。
- [ ] 记录未能运行的测试和原因。
验收证据:
- [ ] 测试结果写入本文件“测试记录”。
## 6. 评测集
- [ ] 准备 5 条报销问题。
- [ ] 准备 5 条应收问题。
- [ ] 准备 5 条应付问题。
- [ ] 准备 3 条规则解释问题。
- [ ] 准备 3 条越权动作问题。
- [ ] 执行语义解析评测。
- [ ] 执行 User Agent 回答评测。
- [ ] 执行权限拦截评测。
- [ ] 记录失败样例。
- [ ] 为失败样例写下一阶段优化建议。
验收证据:
- [ ] 可以说明 MVP 当前能力边界和准确率风险。
## 7. 演示数据
- [ ] 准备 active 规则。
- [ ] 准备 pending 规则。
- [ ] 准备 rejected 规则。
- [ ] 准备至少一条报销数据。
- [ ] 准备至少一条应收数据。
- [ ] 准备至少一条应付数据。
- [ ] 准备至少一个 Hermes 任务。
- [ ] 准备至少一个 MCP Mock。
- [ ] 准备至少一个知识条目。
- [ ] 准备至少一个风险样例。
验收证据:
- [ ] 演示不会因为没有数据而中断。
## 8. 演示脚本
- [ ] 编写演示步骤 1打开任务规则中心。
- [ ] 编写演示步骤 2查看规则详情。
- [ ] 编写演示步骤 3编辑 Markdown 并保存。
- [ ] 编写演示步骤 4切换版本。
- [ ] 编写演示步骤 5尝试上线未审核规则并被拦截。
- [ ] 编写演示步骤 6输入用户问题。
- [ ] 编写演示步骤 7查看语义本体结果。
- [ ] 编写演示步骤 8查看 User Agent 回答。
- [ ] 编写演示步骤 9手动触发 Hermes 任务。
- [ ] 编写演示步骤 10查看 AgentRun Trace。
- [ ] 编写演示步骤 11查看审计日志。
验收证据:
- [ ] 新开发者按脚本可以复现演示。
## 9. 文档收尾
- [ ] 更新一周计划完成情况。
- [ ] 更新剩余风险。
- [ ] 更新下一阶段开发建议。
- [ ] 更新接口清单。
- [ ] 更新数据模型清单。
- [ ] 更新前端页面清单。
- [ ] 更新评测结果。
- [ ] 更新演示脚本。
- [ ] 更新部署或启动说明。
验收证据:
- [ ] 文档能指导下一周继续开发。
## 10. 最终验收清单
- [ ] 任务规则中心可查看规则、技能、MCP、任务。
- [ ] 规则详情可编辑 Markdown。
- [ ] 规则详情可查看最近 5 个版本。
- [ ] 版本切换有确认弹窗。
- [ ] 审核者信息可见。
- [ ] 未审核规则不能上线。
- [ ] 语义本体 8 字段可返回。
- [ ] Orchestrator 能路由用户请求。
- [ ] Orchestrator 能路由定时任务。
- [ ] User Agent 能回答至少 3 类财务问题。
- [ ] Hermes 能执行至少 1 个任务。
- [ ] OCR Mock 接入点可用。
- [ ] 知识候选可生成。
- [ ] 规则草稿可生成。
- [ ] AgentRun Trace 可查。
- [ ] AuditLog 可查。
- [ ] 前端构建通过。
- [ ] 后端核心测试通过。
- [ ] 演示脚本可执行。
- [ ] 所有完成项已用 `[x] ~~...~~` 标记。
## 测试记录
- [ ] 后端测试:未运行。
- [ ] 前端构建:未运行。
- [ ] 语义评测:未运行。
- [ ] 手动验收:未运行。
## 阻塞记录
- [ ] 暂无。
## 日终交接
- [ ] 写明本周最终完成内容。
- [ ] 写明未完成内容。
- [ ] 写明生产化前必须补齐内容。
- [ ] 写明下一周建议优先级。

View File

@@ -1,137 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Day 1 - 基础模型与工程骨架</title>
<link rel="stylesheet" href="./styles.css">
</head>
<body>
<div class="shell">
<div class="topbar">
<a class="brand" href="./index.html"><span class="brand-mark">D1</span><span>Day 1 View</span></a>
<div class="quick-links">
<a class="pill" href="./index.html">返回总览</a>
<a class="pill" href="../agent%20week%20plan/day_1_foundation_models.md">周计划原文</a>
<a class="pill" href="../agent%20week%20plan/day_1_foundation_models.md">合并文档原文</a>
</div>
</div>
<div class="day-nav">
<a class="pill active" href="./day-1.html">Day 1</a>
<a class="pill" href="./day-2.html">Day 2</a>
<a class="pill" href="./day-3.html">Day 3</a>
<a class="pill" href="./day-4.html">Day 4</a>
<a class="pill" href="./day-5.html">Day 5</a>
<a class="pill" href="./day-6.html">Day 6</a>
<a class="pill" href="./day-7.html">Day 7</a>
</div>
<section class="hero">
<div class="hero-badge">Foundation Completed</div>
<h1>Day 1 基础模型与工程骨架</h1>
<p>这一天的任务不是做炫目的业务能力,而是把后面 6 天要反复依赖的模型、版本、审核、run trace、审计日志和最小业务数据源一次定稳。Day 1 做虚了Day 4 到 Day 6 会全部返工。</p>
<div class="hero-meta">
<div class="meta-card"><div class="meta-label">当前状态</div><div class="meta-value">已完成2026-05-11可直接进入 Day 2 联调。</div></div>
<div class="meta-card"><div class="meta-label">上游依赖</div><div class="meta-value">Day 1 是全周底座。</div></div>
<div class="meta-card"><div class="meta-label">下游交接</div><div class="meta-value">Day 2 资产 APIDay 3 解析日志Day 4 run traceDay 5/6 业务数据查询。</div></div>
<div class="meta-card"><div class="meta-label">当天关键</div><div class="meta-value">先确定统一模型,再接 API 骨架和种子数据。</div></div>
</div>
</section>
<div class="section-kicker">Three-Layer Mapping</div>
<h2 class="section-title">三层文档映射</h2>
<div class="grid three">
<section class="card tone-warm">
<h3>路线图</h3>
<p>周计划里定义这一天要完成“工程地基”强调只做稳定模型、API 骨架、种子数据、基础审计和可运行验证。</p>
<div class="card-links"><a class="link-chip" href="../agent%20week%20plan/day_1_foundation_models.md">day_1_foundation_models.md</a></div>
</section>
<section class="card tone-teal">
<h3>执行细则</h3>
<p>执行层把 Day 1 拆成命名边界、最小财务业务数据模型、Agent 资产模型、版本、审核、Run、ToolCall、SemanticParseLog、AuditLog、Schema、API、服务层。</p>
<div class="card-links"><a class="link-chip" href="../agent%20week%20plan/day_1_foundation_models.md">agent week plan/day_1</a></div>
</section>
<section class="card tone-olive">
<h3>架构依据</h3>
<p>主要受总体架构、语义本体、数据契约、能力注册、权限确认、可观测性和财务标准模型约束。</p>
<div class="card-links">
<a class="link-chip" href="../agent%20plan/01_overall_architecture.md">01</a>
<a class="link-chip" href="../agent%20plan/02_semantic_ontology.md">02</a>
<a class="link-chip" href="../agent%20plan/06_data_contracts_and_governance.md">06</a>
<a class="link-chip" href="../agent%20plan/07_capability_registry.md">07</a>
<a class="link-chip" href="../agent%20plan/08_permission_confirmation.md">08</a>
<a class="link-chip" href="../agent%20plan/09_observability_and_trace.md">09</a>
<a class="link-chip" href="../agent%20plan/14_financial_document_canonical_model.md">14</a>
</div>
</section>
</div>
<div class="section-kicker">Build Order</div>
<h2 class="section-title">推荐开发顺序</h2>
<div class="timeline">
<div class="timeline-step"><strong>Step 1</strong>先确认后端目录、ORM、迁移方式、测试目录和不该碰的文件。</div>
<div class="timeline-step"><strong>Step 2</strong>统一命名资产类型、状态、审核状态、Agent、权限级别。</div>
<div class="timeline-step"><strong>Step 3</strong>补最小财务业务数据模型:<code>expense_claims</code><code>accounts_receivable</code><code>accounts_payable</code></div>
<div class="timeline-step"><strong>Step 4</strong>完成 AgentAsset、Version、Review、Run、ToolCall、ParseLog、AuditLog。</div>
<div class="timeline-step"><strong>Step 5</strong>把 Schema、API 骨架、服务层、种子数据接起来。</div>
</div>
<div class="section-kicker">Must Deliver</div>
<h2 class="section-title">今天必须产出的东西</h2>
<div class="grid two">
<section class="card">
<h3>平台底座表</h3>
<ul class="list">
<li><code>AgentAsset</code><code>AgentAssetVersion</code><code>AgentAssetReview</code></li>
<li><code>AgentRun</code><code>AgentToolCall</code><code>SemanticParseLog</code></li>
<li><code>AuditLog</code></li>
</ul>
</section>
<section class="card">
<h3>最小业务数据来源</h3>
<ul class="list">
<li>报销至少有时间、地点、理由、金额、员工、部门、状态。</li>
<li>应收至少有客户、金额、未收金额、到期日、账龄、状态。</li>
<li>应付至少有供应商、金额、未付金额、到期日、账龄、状态。</li>
</ul>
</section>
<section class="card">
<h3>API 骨架</h3>
<ul class="list">
<li>资产列表 / 详情 / 版本 / 审核 / 上线。</li>
<li>运行日志与审计日志查询。</li>
<li>返回真实数据库结果,不用前端硬编码收尾。</li>
</ul>
</section>
<section class="card">
<h3>统一服务边界</h3>
<ul class="list">
<li>上线拦截逻辑在服务层,不堆到路由。</li>
<li>所有写操作要留审计接口。</li>
<li>任何 Agent 执行记录都必须生成 <code>run_id</code></li>
</ul>
</section>
</div>
<div class="section-kicker">Acceptance Snapshot</div>
<h2 class="section-title">验收快照</h2>
<div class="table-like">
<div class="row"><div class="row-label">资产模型</div><div class="row-value">已落地 3 条规则、2 条技能、2 条 MCP、3 条任务,并可通过资产接口返回。</div></div>
<div class="row"><div class="row-label">版本与审核</div><div class="row-value">三条规则都具备版本历史;同一资产版本号不可重复,未审核规则不能上线。</div></div>
<div class="row"><div class="row-label">运行与错误</div><div class="row-value">`GET /api/v1/agent-runs` 可返回 3 条运行日志,任意新建 Run 自动生成 <code>run_id</code></div></div>
<div class="row"><div class="row-label">最小业务表</div><div class="row-value">报销、应收、应付种子数据已就位,后续查询和风险巡检都有明确数据来源。</div></div>
</div>
<div class="section-kicker">Common Misses</div>
<h2 class="section-title">这一天最容易漏掉的点</h2>
<ul class="list">
<li>只建 Agent 表,不建最小财务业务表,导致 User Agent 和 Hermes 后面无数据可查。</li>
<li>把审核拦截塞在 API 路由里,后面很难复用到 Orchestrator 和别的入口。</li>
<li>没有统一 <code>run_id</code> 和审计接口Day 4 到 Day 7 的 Trace 会断链。</li>
</ul>
<div class="footer">Day 1 的判断标准很简单:不是“代码写了多少”,而是“后面 6 天会不会反复回头补地基”。</div>
</div>
</body>
</html>

View File

@@ -1,132 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Day 2 - 任务规则中心联调</title>
<link rel="stylesheet" href="./styles.css">
</head>
<body>
<div class="shell">
<div class="topbar">
<a class="brand" href="./index.html"><span class="brand-mark">D2</span><span>Day 2 View</span></a>
<div class="quick-links">
<a class="pill" href="./index.html">返回总览</a>
<a class="pill" href="../agent%20week%20plan/day_2_rule_center_integration.md">周计划原文</a>
<a class="pill" href="../agent%20week%20plan/day_2_rule_center_integration.md">合并文档原文</a>
</div>
</div>
<div class="day-nav">
<a class="pill" href="./day-1.html">Day 1</a>
<a class="pill active" href="./day-2.html">Day 2</a>
<a class="pill" href="./day-3.html">Day 3</a>
<a class="pill" href="./day-4.html">Day 4</a>
<a class="pill" href="./day-5.html">Day 5</a>
<a class="pill" href="./day-6.html">Day 6</a>
<a class="pill" href="./day-7.html">Day 7</a>
</div>
<section class="hero">
<div class="hero-badge">Integration</div>
<h1>Day 2 任务规则中心联调</h1>
<p>Day 2 的核心不是“把页面做漂亮”而是让规则、技能、MCP、任务这四类资产第一次脱离本地假数据真正连到 Day 1 的数据库和 API。最关键的能力是 Markdown、版本、审核和上线约束闭环。</p>
<div class="hero-meta">
<div class="meta-card"><div class="meta-label">上游依赖</div><div class="meta-value">Day 1 的资产模型、版本模型、审核模型、资产 API。</div></div>
<div class="meta-card"><div class="meta-label">下游交接</div><div class="meta-value">Day 3 要复用资产数据Day 4 要查询 active 技能 / MCP / 任务。</div></div>
<div class="meta-card"><div class="meta-label">当天关键</div><div class="meta-value">前端联调不是硬编码演示,而是可对接真实后端。</div></div>
</div>
</section>
<div class="section-kicker">Three-Layer Mapping</div>
<h2 class="section-title">三层文档映射</h2>
<div class="grid three">
<section class="card tone-warm">
<h3>路线图</h3>
<p>周计划要求把任务规则中心从静态 UI 升级到真实数据对接覆盖规则、技能、MCP、任务四类资产。</p>
<div class="card-links"><a class="link-chip" href="../agent%20week%20plan/day_2_rule_center_integration.md">day_2_rule_center_integration.md</a></div>
</section>
<section class="card tone-teal">
<h3>执行细则</h3>
<p>执行层拆成 API Client、四类列表、规则详情、Markdown 编辑、版本卡片、审核与上线、技能详情、MCP 详情、任务详情、前端质量和当天验收。</p>
<div class="card-links"><a class="link-chip" href="../agent%20week%20plan/day_2_rule_center_integration.md">agent week plan/day_2</a></div>
</section>
<section class="card tone-olive">
<h3>架构依据</h3>
<p>这一天主要受能力注册、规则形成生命周期和数据治理约束,重点在四类资产的统一展示方式和规则上线前审核拦截。</p>
<div class="card-links">
<a class="link-chip" href="../agent%20plan/07_capability_registry.md">07</a>
<a class="link-chip" href="../agent%20plan/13_rule_formation_lifecycle.md">13</a>
<a class="link-chip" href="../agent%20plan/06_data_contracts_and_governance.md">06</a>
</div>
</section>
</div>
<div class="section-kicker">Build Order</div>
<h2 class="section-title">推荐开发顺序</h2>
<div class="timeline">
<div class="timeline-step"><strong>Step 1</strong>先补 API Client列表、详情、版本、保存、审核、上线、运行日志。</div>
<div class="timeline-step"><strong>Step 2</strong>把四个页签的真实数据接起来,覆盖筛选、搜索、状态、空态和加载态。</div>
<div class="timeline-step"><strong>Step 3</strong>把规则详情的 Hero 区、Markdown 编辑器、版本卡片和审核信息拉通。</div>
<div class="timeline-step"><strong>Step 4</strong>补技能 / MCP / 任务的差异化详情,不复用规则编辑器。</div>
<div class="timeline-step"><strong>Step 5</strong>最后收 UI 细节、错误态、禁用态、确认弹窗和构建验证。</div>
</div>
<div class="section-kicker">Must Deliver</div>
<h2 class="section-title">今天必须产出的东西</h2>
<div class="grid two">
<section class="card">
<h3>规则中心四页签</h3>
<ul class="list">
<li>规则、技能、MCP、任务都能切换。</li>
<li>每个页签都来自真实接口,不再只读本地常量。</li>
<li>搜索和状态筛选同时生效。</li>
</ul>
</section>
<section class="card">
<h3>规则详情闭环</h3>
<ul class="list">
<li>能读取当前 Markdown。</li>
<li>能保存并刷新版本列表。</li>
<li>能展示审核者、审核状态、上线条件。</li>
</ul>
</section>
<section class="card">
<h3>版本与上线约束</h3>
<ul class="list">
<li>最近 5 个版本可见。</li>
<li>切换旧版本必须弹确认框。</li>
<li>未审核规则不能上线,拒绝原因要可见。</li>
</ul>
</section>
<section class="card">
<h3>详情差异化</h3>
<ul class="list">
<li>技能详情展示输入输出与依赖。</li>
<li>MCP 详情展示服务地址、鉴权、降级策略。</li>
<li>任务详情展示 cron、执行 Agent、最近执行结果。</li>
</ul>
</section>
</div>
<div class="section-kicker">Acceptance Snapshot</div>
<h2 class="section-title">验收快照</h2>
<div class="table-like">
<div class="row"><div class="row-label">真实数据</div><div class="row-value">四个页签都能用真实后端数据渲染,后端不可用时有明确错误提示。</div></div>
<div class="row"><div class="row-label">规则编辑</div><div class="row-value">Markdown 保存后刷新页面仍在,保存失败不丢输入。</div></div>
<div class="row"><div class="row-label">版本卡片</div><div class="row-value">最近 5 个版本可切换,当前版本标识清楚但不造成布局位移。</div></div>
<div class="row"><div class="row-label">审核上线</div><div class="row-value"><code>pending</code> / <code>rejected</code> 规则都无法上线,<code>approved</code> 才能放行。</div></div>
</div>
<div class="section-kicker">Common Misses</div>
<h2 class="section-title">这一天最容易漏掉的点</h2>
<ul class="list">
<li>只把规则页签接成真实数据技能、MCP、任务仍然靠假数据撑场面。</li>
<li>只做版本列表展示,不做确认弹窗和拒绝风险提示。</li>
<li>把任务写成“定时任务”暴露给用户,违背文档里 UI 名称统一成“任务”的约束。</li>
</ul>
<div class="footer">Day 2 的完成标准不是“页面能打开”,而是“规则中心第一次成为真实的资产入口”。</div>
</div>
</body>
</html>

View File

@@ -1,132 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Day 3 - 语义本体 MVP</title>
<link rel="stylesheet" href="./styles.css">
</head>
<body>
<div class="shell">
<div class="topbar">
<a class="brand" href="./index.html"><span class="brand-mark">D3</span><span>Day 3 View</span></a>
<div class="quick-links">
<a class="pill" href="./index.html">返回总览</a>
<a class="pill" href="../agent%20week%20plan/day_3_semantic_ontology_mvp.md">周计划原文</a>
<a class="pill" href="../agent%20week%20plan/day_3_semantic_ontology_mvp.md">合并文档原文</a>
</div>
</div>
<div class="day-nav">
<a class="pill" href="./day-1.html">Day 1</a>
<a class="pill" href="./day-2.html">Day 2</a>
<a class="pill active" href="./day-3.html">Day 3</a>
<a class="pill" href="./day-4.html">Day 4</a>
<a class="pill" href="./day-5.html">Day 5</a>
<a class="pill" href="./day-6.html">Day 6</a>
<a class="pill" href="./day-7.html">Day 7</a>
</div>
<section class="hero">
<div class="hero-badge">Ontology</div>
<h1>Day 3 语义本体 MVP</h1>
<p>这一天把自然语言问题统一切成 8 个核心字段。Day 3 不是追求大模型多聪明,而是先让结构稳定、可落日志、可被 Orchestrator、User Agent 和 Hermes 共用。</p>
<div class="hero-meta">
<div class="meta-card"><div class="meta-label">上游依赖</div><div class="meta-value">Day 1 的 <code>SemanticParseLog</code> / <code>AgentRun</code>Day 2 的资产 API。</div></div>
<div class="meta-card"><div class="meta-label">下游交接</div><div class="meta-value">Day 4 路由、Day 5 查询解释、Day 6 风险巡检都直接消费这 8 字段。</div></div>
<div class="meta-card"><div class="meta-label">当天关键</div><div class="meta-value">名字统一、类型统一、日志统一、低置信度有澄清问题。</div></div>
</div>
</section>
<div class="section-kicker">Three-Layer Mapping</div>
<h2 class="section-title">三层文档映射</h2>
<div class="grid three">
<section class="card tone-warm">
<h3>路线图</h3>
<p>周计划要求建立用户问题的统一语义解析层,覆盖场景、意图、对象、时间、指标、约束、风险、权限 8 字段。</p>
<div class="card-links"><a class="link-chip" href="../agent%20week%20plan/day_3_semantic_ontology_mvp.md">day_3_semantic_ontology_mvp.md</a></div>
</section>
<section class="card tone-teal">
<h3>执行细则</h3>
<p>执行层拆成 8 字段定义、字段枚举、Schema、解析服务、对象提取、时间范围、指标约束、风险权限、API、前端调试入口和评测集。</p>
<div class="card-links"><a class="link-chip" href="../agent%20week%20plan/day_3_semantic_ontology_mvp.md">agent week plan/day_3</a></div>
</section>
<section class="card tone-olive">
<h3>架构依据</h3>
<p>主要受语义本体、财务标准模型和数据治理约束。应收、应付、报销的对象语义必须能回到最小业务表和标准对象。</p>
<div class="card-links">
<a class="link-chip" href="../agent%20plan/02_semantic_ontology.md">02</a>
<a class="link-chip" href="../agent%20plan/14_financial_document_canonical_model.md">14</a>
<a class="link-chip" href="../agent%20plan/06_data_contracts_and_governance.md">06</a>
</div>
</section>
</div>
<div class="section-kicker">Build Order</div>
<h2 class="section-title">推荐开发顺序</h2>
<div class="timeline">
<div class="timeline-step"><strong>Step 1</strong>先固定 8 个字段名字、类型、默认值和示例。</div>
<div class="timeline-step"><strong>Step 2</strong><code>scenario</code><code>intent</code><code>permission.level</code> 的枚举定死。</div>
<div class="timeline-step"><strong>Step 3</strong>做请求/响应 Schema再写解析服务。</div>
<div class="timeline-step"><strong>Step 4</strong>补对象提取、时间范围、指标约束、风险和权限映射。</div>
<div class="timeline-step"><strong>Step 5</strong>接 API、日志、调试入口和最小评测集。</div>
</div>
<div class="section-kicker">Must Deliver</div>
<h2 class="section-title">今天必须产出的东西</h2>
<div class="grid two">
<section class="card">
<h3>8 字段统一结构</h3>
<ul class="list">
<li><code>scenario</code><code>intent</code><code>entities</code><code>time_range</code></li>
<li><code>metrics</code><code>constraints</code><code>risk_flags</code><code>permission</code></li>
<li>附带 <code>confidence</code><code>clarification_required</code><code>run_id</code></li>
</ul>
</section>
<section class="card">
<h3>规则解析优先版</h3>
<ul class="list">
<li>先用关键词和规则解析打底。</li>
<li>报销 / 应收 / 应付 / 知识 / unknown 场景都能落到结构。</li>
<li>越权动作能识别为 <code>approval_required</code><code>forbidden</code></li>
</ul>
</section>
<section class="card">
<h3>日志和调试入口</h3>
<ul class="list">
<li>每次解析都要落 <code>SemanticParseLog</code></li>
<li>前端可直接输入一句话看 8 字段结果。</li>
<li>低置信度问题必须给澄清问题。</li>
</ul>
</section>
<section class="card">
<h3>最小评测集</h3>
<ul class="list">
<li>至少覆盖报销、应收、应付、知识、越权动作。</li>
<li>每条样例要写期望 <code>scenario</code><code>intent</code> 和权限级别。</li>
<li>当天目标是可评测,而不是追求完美准确率。</li>
</ul>
</section>
</div>
<div class="section-kicker">Acceptance Snapshot</div>
<h2 class="section-title">验收快照</h2>
<div class="table-like">
<div class="row"><div class="row-label">语义结构</div><div class="row-value">8 字段在 Schema、服务层、日志里名字完全一致。</div></div>
<div class="row"><div class="row-label">关键识别</div><div class="row-value">“本周报销超标风险”“客户 A 本月应收”“供应商 B 明天要付多少钱”都能落到正确场景和意图。</div></div>
<div class="row"><div class="row-label">权限结果</div><div class="row-value">“帮我直接付款”不能被识别成可直接执行动作。</div></div>
<div class="row"><div class="row-label">日志与前端</div><div class="row-value">连续调用多次都能在日志中查到,并能通过调试入口观察结果。</div></div>
</div>
<div class="section-kicker">Common Misses</div>
<h2 class="section-title">这一天最容易漏掉的点</h2>
<ul class="list">
<li>字段结构和日志结构各写一套名字,后面 Trace 很难串。</li>
<li>只做 <code>scenario</code><code>intent</code>,不做 <code>permission</code>Day 4 会直接失去拦截依据。</li>
<li>只在服务里返回结果,不把解析过程落库或落日志,后续无法复盘误判样例。</li>
</ul>
<div class="footer">Day 3 的价值在于把“语义理解”从模糊文本变成稳定协议。后面所有智能能力都站在这层协议上。</div>
</div>
</body>
</html>

View File

@@ -1,133 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Day 4 - Orchestrator 运行时</title>
<link rel="stylesheet" href="./styles.css">
</head>
<body>
<div class="shell">
<div class="topbar">
<a class="brand" href="./index.html"><span class="brand-mark">D4</span><span>Day 4 View</span></a>
<div class="quick-links">
<a class="pill" href="./index.html">返回总览</a>
<a class="pill" href="../agent%20week%20plan/day_4_orchestrator_runtime.md">周计划原文</a>
<a class="pill" href="../agent%20week%20plan/day_4_orchestrator_runtime.md">合并文档原文</a>
</div>
</div>
<div class="day-nav">
<a class="pill" href="./day-1.html">Day 1</a>
<a class="pill" href="./day-2.html">Day 2</a>
<a class="pill" href="./day-3.html">Day 3</a>
<a class="pill active" href="./day-4.html">Day 4</a>
<a class="pill" href="./day-5.html">Day 5</a>
<a class="pill" href="./day-6.html">Day 6</a>
<a class="pill" href="./day-7.html">Day 7</a>
</div>
<section class="hero">
<div class="hero-badge">Runtime</div>
<h1>Day 4 Orchestrator 运行时</h1>
<p>Day 4 把整个系统第一次串成“能跑的链”。用户消息和定时任务都先走 Orchestrator由它创建 run、调用语义解析、做权限判断、选择 Agent、记录 ToolCall 和 Trace然后再给下游执行。</p>
<div class="hero-meta">
<div class="meta-card"><div class="meta-label">上游依赖</div><div class="meta-value">Day 3 的语义解析结果Day 1 的 Run / ToolCallDay 2 的 active 资产。</div></div>
<div class="meta-card"><div class="meta-label">下游交接</div><div class="meta-value">Day 5 User Agent 和 Day 6 Hermes 都通过它被调度。</div></div>
<div class="meta-card"><div class="meta-label">当天关键</div><div class="meta-value">权限拦截和 Trace 必须在 Orchestrator 层,而不是散落在各 Agent。</div></div>
</div>
</section>
<div class="section-kicker">Three-Layer Mapping</div>
<h2 class="section-title">三层文档映射</h2>
<div class="grid three">
<section class="card tone-warm">
<h3>路线图</h3>
<p>周计划要求建立统一调度层,让用户请求和系统任务都先进入 Orchestrator再根据语义、权限、能力注册路由到 User Agent、Hermes、MCP 或规则引擎。</p>
<div class="card-links"><a class="link-chip" href="../agent%20week%20plan/day_4_orchestrator_runtime.md">day_4_orchestrator_runtime.md</a></div>
</section>
<section class="card tone-teal">
<h3>执行细则</h3>
<p>执行层拆成输入输出、Orchestrator 服务、路由规则、权限判断、能力查询、工具调用封装、API、最小 Trace 查看和测试。</p>
<div class="card-links"><a class="link-chip" href="../agent%20week%20plan/day_4_orchestrator_runtime.md">agent week plan/day_4</a></div>
</section>
<section class="card tone-olive">
<h3>架构依据</h3>
<p>主要受运行时流程、能力注册、权限确认和可观测性约束。Day 4 的输出要能直接给前端展示,并支持 Day 5/6 的占位实现接入。</p>
<div class="card-links">
<a class="link-chip" href="../agent%20plan/04_orchestrator_and_runtime_flow.md">04</a>
<a class="link-chip" href="../agent%20plan/07_capability_registry.md">07</a>
<a class="link-chip" href="../agent%20plan/08_permission_confirmation.md">08</a>
<a class="link-chip" href="../agent%20plan/09_observability_and_trace.md">09</a>
</div>
</section>
</div>
<div class="section-kicker">Build Order</div>
<h2 class="section-title">推荐开发顺序</h2>
<div class="timeline">
<div class="timeline-step"><strong>Step 1</strong>先定 <code>OrchestratorRequest</code><code>OrchestratorResponse</code></div>
<div class="timeline-step"><strong>Step 2</strong><code>run(request)</code> 主流程:创建 Run、解析语义、判权限、选 Agent、更新状态。</div>
<div class="timeline-step"><strong>Step 3</strong>把用户入口 / 任务入口的路由规则固化下来。</div>
<div class="timeline-step"><strong>Step 4</strong>封装工具调用记录和降级策略。</div>
<div class="timeline-step"><strong>Step 5</strong>暴露 API 和最小 Trace 页面或接口。</div>
</div>
<div class="section-kicker">Must Deliver</div>
<h2 class="section-title">今天必须产出的东西</h2>
<div class="grid two">
<section class="card">
<h3>统一入口</h3>
<ul class="list">
<li><code>source=user_message</code><code>source=schedule</code> 都能进同一入口。</li>
<li>请求返回 <code>run_id</code><code>selected_agent</code><code>route_reason</code><code>permission_level</code></li>
<li>返回结果要能被前端直接展示。</li>
</ul>
</section>
<section class="card">
<h3>权限与路由</h3>
<ul class="list">
<li>查询类走 User Agent定时风险类走 Hermes。</li>
<li><code>approval_required</code> 只返回确认,不直接执行。</li>
<li><code>forbidden</code> 直接阻断,不调下游 Agent。</li>
</ul>
</section>
<section class="card">
<h3>能力与工具调用</h3>
<ul class="list">
<li>只查询 active 技能 / MCP / 任务。</li>
<li>禁用能力不允许被调用。</li>
<li>每次工具调用都能落 <code>AgentToolCall</code></li>
</ul>
</section>
<section class="card">
<h3>Trace 与降级</h3>
<ul class="list">
<li>Trace 能串起语义解析、路由、工具调用和最终结果。</li>
<li>外部 MCP 失败要返回降级说明,不让前端拿到不可读错误。</li>
<li>异常都要写进 <code>AgentRun.error_message</code></li>
</ul>
</section>
</div>
<div class="section-kicker">Acceptance Snapshot</div>
<h2 class="section-title">验收快照</h2>
<div class="table-like">
<div class="row"><div class="row-label">路由结果</div><div class="row-value">同一句风险检查,在用户入口和任务入口会有不同路由结果。</div></div>
<div class="row"><div class="row-label">权限边界</div><div class="row-value">“直接上线规则”和“直接付款”都不会被自动执行。</div></div>
<div class="row"><div class="row-label">日志完整度</div><div class="row-value">每次运行至少有一条 <code>AgentRun</code>,工具调用有 0 到多条 <code>AgentToolCall</code></div></div>
<div class="row"><div class="row-label">可观察性</div><div class="row-value">前端或 curl 可以完整看到一次运行链路,不需要直接查数据库猜过程。</div></div>
</div>
<div class="section-kicker">Common Misses</div>
<h2 class="section-title">这一天最容易漏掉的点</h2>
<ul class="list">
<li>把权限判断放到 User Agent / Hermes 内部,导致系统没有统一边界。</li>
<li>只记录成功 ToolCall不记录失败 ToolCall后面降级和排错会缺证据。</li>
<li>路由能跑,但没有统一 Trace 输出Day 7 演示时会非常难讲清链路。</li>
</ul>
<div class="footer">Day 4 的价值是把系统从“有很多零件”变成“有一条统一运行链”。</div>
</div>
</body>
</html>

View File

@@ -1,133 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Day 5 - User Agent MVP</title>
<link rel="stylesheet" href="./styles.css">
</head>
<body>
<div class="shell">
<div class="topbar">
<a class="brand" href="./index.html"><span class="brand-mark">D5</span><span>Day 5 View</span></a>
<div class="quick-links">
<a class="pill" href="./index.html">返回总览</a>
<a class="pill" href="../agent%20week%20plan/day_5_user_agent_mvp.md">周计划原文</a>
<a class="pill" href="../agent%20week%20plan/day_5_user_agent_mvp.md">合并文档原文</a>
</div>
</div>
<div class="day-nav">
<a class="pill" href="./day-1.html">Day 1</a>
<a class="pill" href="./day-2.html">Day 2</a>
<a class="pill" href="./day-3.html">Day 3</a>
<a class="pill" href="./day-4.html">Day 4</a>
<a class="pill active" href="./day-5.html">Day 5</a>
<a class="pill" href="./day-6.html">Day 6</a>
<a class="pill" href="./day-7.html">Day 7</a>
</div>
<section class="hero">
<div class="hero-badge">User Agent</div>
<h1>Day 5 User Agent MVP</h1>
<p>这一天开始让“用户真的能问问题”。但 User Agent 只负责查询、解释、规则引用和草稿生成,绝不绕过权限做审批、付款、上线这类高风险动作。</p>
<div class="hero-meta">
<div class="meta-card"><div class="meta-label">上游依赖</div><div class="meta-value">Day 4 Orchestrator、Day 3 语义结构、Day 1 业务数据与日志模型、Day 2 规则资产。</div></div>
<div class="meta-card"><div class="meta-label">下游交接</div><div class="meta-value">Day 7 要拿它做问答演示、规则解释演示和草稿生成演示。</div></div>
<div class="meta-card"><div class="meta-label">当天关键</div><div class="meta-value">回答可读、引用可追溯、草稿可确认、高风险不自动执行。</div></div>
</div>
</section>
<div class="section-kicker">Three-Layer Mapping</div>
<h2 class="section-title">三层文档映射</h2>
<div class="grid three">
<section class="card tone-warm">
<h3>路线图</h3>
<p>周计划要求做用户自然语言入口、报销 / 应收 / 应付查询解释、规则引用解释、建议草稿和前端入口。</p>
<div class="card-links"><a class="link-chip" href="../agent%20week%20plan/day_5_user_agent_mvp.md">day_5_user_agent_mvp.md</a></div>
</section>
<section class="card tone-teal">
<h3>执行细则</h3>
<p>执行层拆成输入输出、查询处理、规则解释、风险解释、草稿生成、知识库读取骨架、对话入口、安全边界和测试。</p>
<div class="card-links"><a class="link-chip" href="../agent%20week%20plan/day_5_user_agent_mvp.md">agent week plan/day_5</a></div>
</section>
<section class="card tone-olive">
<h3>架构依据</h3>
<p>主要受 Agent 职责划分、运行时流程、知识架构和规则形成生命周期约束。所有高风险动作只能停留在建议或草稿层。</p>
<div class="card-links">
<a class="link-chip" href="../agent%20plan/03_agent_responsibilities.md">03</a>
<a class="link-chip" href="../agent%20plan/04_orchestrator_and_runtime_flow.md">04</a>
<a class="link-chip" href="../agent%20plan/12_llm_wiki_knowledge_architecture.md">12</a>
<a class="link-chip" href="../agent%20plan/13_rule_formation_lifecycle.md">13</a>
</div>
</section>
</div>
<div class="section-kicker">Build Order</div>
<h2 class="section-title">推荐开发顺序</h2>
<div class="timeline">
<div class="timeline-step"><strong>Step 1</strong>先定 <code>UserAgentRequest</code> / <code>UserAgentResponse</code> 协议。</div>
<div class="timeline-step"><strong>Step 2</strong>优先实现报销、应收、应付查询处理器。</div>
<div class="timeline-step"><strong>Step 3</strong>补规则解释和风险解释,让回答有依据而不是只给一句话。</div>
<div class="timeline-step"><strong>Step 4</strong>补草稿生成与知识读取骨架。</div>
<div class="timeline-step"><strong>Step 5</strong>最后接前端问答入口、加载态、错误态和确认提示。</div>
</div>
<div class="section-kicker">Must Deliver</div>
<h2 class="section-title">今天必须产出的东西</h2>
<div class="grid two">
<section class="card">
<h3>三类财务查询</h3>
<ul class="list">
<li>报销查询可读,能查金额、状态或进度。</li>
<li>应收查询可读,能查客户未收金额或账龄。</li>
<li>应付查询可读,能查供应商待付款或付款状态。</li>
</ul>
</section>
<section class="card">
<h3>解释能力</h3>
<ul class="list">
<li>规则解释能引用 active 规则、版本号和更新时间。</li>
<li>风险解释能说明风险类型、原因和建议动作。</li>
<li>知识库不可用时要优雅降级。</li>
</ul>
</section>
<section class="card">
<h3>草稿而非执行</h3>
<ul class="list">
<li>可生成报销处理意见草稿、应收催收建议草稿、应付付款建议草稿。</li>
<li>草稿必须写明“待人工确认”。</li>
<li>草稿行为写入审计日志和 AgentRun 结果。</li>
</ul>
</section>
<section class="card">
<h3>用户入口</h3>
<ul class="list">
<li>前端输入框走 Orchestrator不绕行。</li>
<li>显示回答、引用、建议动作、确认提示和 <code>run_id</code></li>
<li>有加载态和错误态。</li>
</ul>
</section>
</div>
<div class="section-kicker">Acceptance Snapshot</div>
<h2 class="section-title">验收快照</h2>
<div class="table-like">
<div class="row"><div class="row-label">问答闭环</div><div class="row-value">用户在页面上能完成一次自然语言提问、拿到回答、看到引用和 run_id。</div></div>
<div class="row"><div class="row-label">三类场景</div><div class="row-value">至少报销、应收、应付三类财务问题都有结构化回答。</div></div>
<div class="row"><div class="row-label">引用能力</div><div class="row-value">“为什么这笔报销有风险”这类问题能引用规则,而不是只给模糊判断。</div></div>
<div class="row"><div class="row-label">安全边界</div><div class="row-value">“直接付款”“直接审批”类提示不会自动执行,只能变成建议或草稿。</div></div>
</div>
<div class="section-kicker">Common Misses</div>
<h2 class="section-title">这一天最容易漏掉的点</h2>
<ul class="list">
<li>只返回原始查询数据,不把结果翻译成用户可读回答。</li>
<li>只做草稿内容,不做 <code>requires_confirmation</code> 和审计日志。</li>
<li>绕过 Orchestrator 直接从前端打 User Agent导致 Day 4 的统一链路失效。</li>
</ul>
<div class="footer">Day 5 的判断标准是:用户能问、系统能答、回答有依据、动作不越权。</div>
</div>
</body>
</html>

View File

@@ -1,133 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Day 6 - Hermes MVP</title>
<link rel="stylesheet" href="./styles.css">
</head>
<body>
<div class="shell">
<div class="topbar">
<a class="brand" href="./index.html"><span class="brand-mark">D6</span><span>Day 6 View</span></a>
<div class="quick-links">
<a class="pill" href="./index.html">返回总览</a>
<a class="pill" href="../agent%20week%20plan/day_6_hermes_mvp.md">周计划原文</a>
<a class="pill" href="../agent%20week%20plan/day_6_hermes_mvp.md">合并文档原文</a>
</div>
</div>
<div class="day-nav">
<a class="pill" href="./day-1.html">Day 1</a>
<a class="pill" href="./day-2.html">Day 2</a>
<a class="pill" href="./day-3.html">Day 3</a>
<a class="pill" href="./day-4.html">Day 4</a>
<a class="pill" href="./day-5.html">Day 5</a>
<a class="pill active" href="./day-6.html">Day 6</a>
<a class="pill" href="./day-7.html">Day 7</a>
</div>
<section class="hero">
<div class="hero-badge">Hermes</div>
<h1>Day 6 Hermes MVP</h1>
<p>Hermes 是后台数字员工,不做即时对话,而是负责定时巡检、风险预警、日报统计、知识候选和规则草稿。它的关键不是“会不会说”,而是“任务能不能跑、结果能不能追”。</p>
<div class="hero-meta">
<div class="meta-card"><div class="meta-label">上游依赖</div><div class="meta-value">Day 4 的 Orchestrator 路由Day 1 的任务与日志表Day 3 的语义结构Day 5 可复用的风险/规则/知识接口。</div></div>
<div class="meta-card"><div class="meta-label">下游交接</div><div class="meta-value">Day 7 要用它做手动触发任务、查看结果、展示规则草稿和知识候选。</div></div>
<div class="meta-card"><div class="meta-label">当天关键</div><div class="meta-value">任务入口、风险项结构、OCR Mock、知识候选和规则草稿都必须可追溯。</div></div>
</div>
</section>
<div class="section-kicker">Three-Layer Mapping</div>
<h2 class="section-title">三层文档映射</h2>
<div class="grid three">
<section class="card tone-warm">
<h3>路线图</h3>
<p>周计划要求实现 Hermes 调度入口、每日风险巡检、统计任务、知识库维护、OCR Mock 和运行结果面板或 API。</p>
<div class="card-links"><a class="link-chip" href="../agent%20week%20plan/day_6_hermes_mvp.md">day_6_hermes_mvp.md</a></div>
</section>
<section class="card tone-teal">
<h3>执行细则</h3>
<p>执行层拆成输入输出、任务调度入口、风险巡检、每日统计、OCR 接入点、知识库维护、规则草稿形成、结果展示和测试。</p>
<div class="card-links"><a class="link-chip" href="../agent%20week%20plan/day_6_hermes_mvp.md">agent week plan/day_6</a></div>
</section>
<section class="card tone-olive">
<h3>架构依据</h3>
<p>主要受 Agent 职责、OCR 架构、知识库架构和反馈学习闭环约束。Hermes 能生成候选和草稿,但不能自动发布正式结果。</p>
<div class="card-links">
<a class="link-chip" href="../agent%20plan/03_agent_responsibilities.md">03</a>
<a class="link-chip" href="../agent%20plan/11_ocr_invoice_architecture.md">11</a>
<a class="link-chip" href="../agent%20plan/12_llm_wiki_knowledge_architecture.md">12</a>
<a class="link-chip" href="../agent%20plan/15_feedback_learning_loop.md">15</a>
</div>
</section>
</div>
<div class="section-kicker">Build Order</div>
<h2 class="section-title">推荐开发顺序</h2>
<div class="timeline">
<div class="timeline-step"><strong>Step 1</strong>先定 <code>HermesTaskRequest</code> / <code>HermesTaskResult</code></div>
<div class="timeline-step"><strong>Step 2</strong>建立手动触发任务 API经 Orchestrator 路由到 Hermes。</div>
<div class="timeline-step"><strong>Step 3</strong>补风险巡检和每日统计的结构化输出。</div>
<div class="timeline-step"><strong>Step 4</strong>接入 OCR Mock、知识候选生成、规则草稿生成。</div>
<div class="timeline-step"><strong>Step 5</strong>补任务详情展示、错误信息和测试。</div>
</div>
<div class="section-kicker">Must Deliver</div>
<h2 class="section-title">今天必须产出的东西</h2>
<div class="grid two">
<section class="card">
<h3>任务调度入口</h3>
<ul class="list">
<li>可手动触发至少一个任务资产。</li>
<li>任务经 Orchestrator 进入 Hermes。</li>
<li>结束后能更新最近执行时间和状态。</li>
</ul>
</section>
<section class="card">
<h3>风险与统计</h3>
<ul class="list">
<li>重复报销、金额超标、应收逾期、应付异常付款等风险有结构化输出。</li>
<li>日报包含报销、报账、应收、应付的关键统计口径。</li>
<li>每个风险项都要能被业务人员理解和追溯。</li>
</ul>
</section>
<section class="card">
<h3>知识候选与规则草稿</h3>
<ul class="list">
<li>知识候选默认是 <code>draft</code>,不能自动发布。</li>
<li>规则草稿保存为 <code>asset_type=rule</code>,状态为 <code>draft</code></li>
<li>两类生成都要写审计日志。</li>
</ul>
</section>
<section class="card">
<h3>OCR Mock 与结果展示</h3>
<ul class="list">
<li>OCR 服务接口和输入输出结构定下来。</li>
<li>当前阶段允许完全使用 Mock 结果。</li>
<li>任务详情或运行日志中能直接看到 Hermes 的执行结果。</li>
</ul>
</section>
</div>
<div class="section-kicker">Acceptance Snapshot</div>
<h2 class="section-title">验收快照</h2>
<div class="table-like">
<div class="row"><div class="row-label">任务可触发</div><div class="row-value">至少一个任务可以手动触发,并能查到结构化结果。</div></div>
<div class="row"><div class="row-label">风险巡检</div><div class="row-value">输出里能看到风险类型、业务对象、触发规则、建议动作和风险等级。</div></div>
<div class="row"><div class="row-label">候选与草稿</div><div class="row-value">知识候选和规则草稿都能生成,但都不是 active / published 正式状态。</div></div>
<div class="row"><div class="row-label">可观察性</div><div class="row-value">不用查数据库,也能从任务详情或运行日志判断 Hermes 是否执行成功。</div></div>
</div>
<div class="section-kicker">Common Misses</div>
<h2 class="section-title">这一天最容易漏掉的点</h2>
<ul class="list">
<li>只做 Hermes 服务逻辑,不做任务入口和结果展示,最后无法演示。</li>
<li>能生成知识或规则,但没把状态锁在 <code>draft</code>,会直接越过人工审核边界。</li>
<li>OCR Mock 只返回一段自由文本,不定义结构字段,后面无法和规则或风险逻辑对接。</li>
</ul>
<div class="footer">Day 6 的价值是让“后台数字员工”第一次具备可触发、可解释、可留痕的闭环。</div>
</div>
</body>
</html>

View File

@@ -1,132 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Day 7 - 加固、演示和验收</title>
<link rel="stylesheet" href="./styles.css">
</head>
<body>
<div class="shell">
<div class="topbar">
<a class="brand" href="./index.html"><span class="brand-mark">D7</span><span>Day 7 View</span></a>
<div class="quick-links">
<a class="pill" href="./index.html">返回总览</a>
<a class="pill" href="../agent%20week%20plan/day_7_hardening_demo_acceptance.md">周计划原文</a>
<a class="pill" href="../agent%20week%20plan/day_7_hardening_demo_acceptance.md">合并文档原文</a>
</div>
</div>
<div class="day-nav">
<a class="pill" href="./day-1.html">Day 1</a>
<a class="pill" href="./day-2.html">Day 2</a>
<a class="pill" href="./day-3.html">Day 3</a>
<a class="pill" href="./day-4.html">Day 4</a>
<a class="pill" href="./day-5.html">Day 5</a>
<a class="pill" href="./day-6.html">Day 6</a>
<a class="pill active" href="./day-7.html">Day 7</a>
</div>
<section class="hero">
<div class="hero-badge">Hardening</div>
<h1>Day 7 加固、演示和验收</h1>
<p>Day 7 不再追求新增大功能,而是把 Day 1 到 Day 6 的链路整理成“可演示、可验收、可继续接手”的状态。没有这一层收口,前面做出来的东西很容易停在“只有作者自己懂”的阶段。</p>
<div class="hero-meta">
<div class="meta-card"><div class="meta-label">上游依赖</div><div class="meta-value">Day 1 到 Day 6 的全部核心路径。</div></div>
<div class="meta-card"><div class="meta-label">当天输出</div><div class="meta-value">回归记录、权限边界、审计和 Trace 补齐、测试记录、演示脚本、交接说明。</div></div>
<div class="meta-card"><div class="meta-label">当天关键</div><div class="meta-value">冻结新增需求,只收验收相关缺口。</div></div>
</div>
</section>
<div class="section-kicker">Three-Layer Mapping</div>
<h2 class="section-title">三层文档映射</h2>
<div class="grid three">
<section class="card tone-warm">
<h3>路线图</h3>
<p>周计划要求完成回归、权限补齐、审计补齐、错误态和空态、评测、演示数据、构建和交付说明。</p>
<div class="card-links"><a class="link-chip" href="../agent%20week%20plan/day_7_hardening_demo_acceptance.md">day_7_hardening_demo_acceptance.md</a></div>
</section>
<section class="card tone-teal">
<h3>执行细则</h3>
<p>执行层拆成核心链路回归、权限和风险边界、审计和 Trace、前端体验修补、测试补齐、评测集、演示数据、演示脚本和文档收尾。</p>
<div class="card-links"><a class="link-chip" href="../agent%20week%20plan/day_7_hardening_demo_acceptance.md">agent week plan/day_7</a></div>
</section>
<section class="card tone-olive">
<h3>架构依据</h3>
<p>主要受整体 README、开发路线图、可观测性和评测集约束。Day 7 的本质是把所有边界和证据讲清楚。</p>
<div class="card-links">
<a class="link-chip" href="../agent%20plan/00_README.md">00</a>
<a class="link-chip" href="../agent%20plan/05_development_roadmap.md">05</a>
<a class="link-chip" href="../agent%20plan/09_observability_and_trace.md">09</a>
<a class="link-chip" href="../agent%20plan/10_evaluation_and_testset.md">10</a>
</div>
</section>
</div>
<div class="section-kicker">Build Order</div>
<h2 class="section-title">推荐收口顺序</h2>
<div class="timeline">
<div class="timeline-step"><strong>Step 1</strong>先汇总 Day 1 到 Day 6 未完成项,冻结新增需求。</div>
<div class="timeline-step"><strong>Step 2</strong>回归核心链路资产、规则、语义解析、Orchestrator、User Agent、Hermes、Trace、AuditLog。</div>
<div class="timeline-step"><strong>Step 3</strong>补权限边界与高风险动作拦截。</div>
<div class="timeline-step"><strong>Step 4</strong>补测试、评测、演示数据和前端体验问题。</div>
<div class="timeline-step"><strong>Step 5</strong>写演示脚本和交接说明,形成最终交付。</div>
</div>
<div class="section-kicker">Must Deliver</div>
<h2 class="section-title">今天必须产出的东西</h2>
<div class="grid two">
<section class="card">
<h3>回归与边界</h3>
<ul class="list">
<li>未审核规则不能上线。</li>
<li>付款、审批、上线等高风险动作都不能绕过确认。</li>
<li>disabled 能力不能被调用。</li>
</ul>
</section>
<section class="card">
<h3>审计与 Trace</h3>
<ul class="list">
<li>规则保存、审核、上线都能看到 AuditLog。</li>
<li>Hermes 生成知识候选 / 规则草稿有审计。</li>
<li>任意演示路径都能追到 <code>run_id</code></li>
</ul>
</section>
<section class="card">
<h3>测试、评测、演示数据</h3>
<ul class="list">
<li>后端测试、前端构建、语义评测至少有执行记录。</li>
<li>报销 / 应收 / 应付 / 风险 / 知识都准备好演示数据。</li>
<li>失败样例和已知边界要明确写出。</li>
</ul>
</section>
<section class="card">
<h3>演示脚本与交接</h3>
<ul class="list">
<li>从任务规则中心、规则详情、版本切换、上线拦截,到 User Agent 问答、Hermes 任务、Trace 和审计,都有明确步骤。</li>
<li>新开发者按脚本能走通一遍。</li>
</ul>
</section>
</div>
<div class="section-kicker">Acceptance Snapshot</div>
<h2 class="section-title">最终验收快照</h2>
<div class="table-like">
<div class="row"><div class="row-label">端到端链路</div><div class="row-value">从规则中心到 User Agent再到 Hermes 和 Trace至少有一条完整演示路径可复现。</div></div>
<div class="row"><div class="row-label">证据完整</div><div class="row-value">AgentRun、ToolCall、AuditLog、测试记录、评测结果和演示脚本都存在。</div></div>
<div class="row"><div class="row-label">风险边界</div><div class="row-value">MVP 期间不存在绕过人工审核、自动付款、自动上线的暗门路径。</div></div>
<div class="row"><div class="row-label">可交接性</div><div class="row-value">下一位开发或 Codex 打开文档就能知道已完成、未完成和生产化前必补项。</div></div>
</div>
<div class="section-kicker">Common Misses</div>
<h2 class="section-title">这一天最容易漏掉的点</h2>
<ul class="list">
<li>只验证 Happy Path不回归错误态、空态、禁用态和被权限拦截路径。</li>
<li>能讲演示,但没有测试记录和已知风险说明,交接质量会很差。</li>
<li>前 6 天的 TODO 没回写完成状态,导致页面和 Markdown 脱节。</li>
</ul>
<div class="footer">Day 7 的目标不是继续堆功能,而是把一周产出变成别人也能运行、理解和接手的系统。</div>
</div>
</body>
</html>

View File

@@ -1,181 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Agent Week Plan HTML</title>
<link rel="stylesheet" href="./styles.css">
</head>
<body>
<div class="shell">
<div class="topbar">
<a class="brand" href="./index.html">
<span class="brand-mark">A7</span>
<span>Agent Week HTML</span>
</a>
<div class="quick-links">
<a class="pill" href="../agent%20week%20plan/MASTER_TODO.md">周计划总控</a>
<a class="pill" href="../agent%20week%20plan/00_README.md">周计划说明</a>
<a class="pill" href="../agent%20plan/00_README.md">架构目录</a>
</div>
</div>
<section class="hero">
<div class="hero-badge">Static Map</div>
<h1>把 7 天周计划变成可直接浏览的开发视图</h1>
<p>这一套 HTML 页面不是替代 Markdown而是把 <code>agent week plan</code><code>agent plan</code> 的对应关系收成一个稳定入口。每天的路线图和执行清单现在已经并到同一份 daily 文档里。</p>
<div class="hero-meta">
<div class="meta-card">
<div class="meta-label">阅读顺序</div>
<div class="meta-value">先总览,再选 Day再跳转到具体 Markdown 落地执行。</div>
</div>
<div class="meta-card">
<div class="meta-label">核心视图</div>
<div class="meta-value">路线图、执行细则、架构依据三层同时可见。</div>
</div>
<div class="meta-card">
<div class="meta-label">适用对象</div>
<div class="meta-value">Codex 开发、后端开发、前端开发、项目 owner、验收人员。</div>
</div>
</div>
</section>
<div class="section-kicker">How To Use</div>
<h2 class="section-title">怎么用这套页面</h2>
<div class="grid two">
<section class="card tone-teal">
<h3>Codex 开发视角</h3>
<ol class="list">
<li>先看今天在哪一天,确认上游依赖和下游交接。</li>
<li>用“两层映射”定位daily 文档看目标和步骤,架构文档看约束。</li>
<li>按“推荐开发顺序”推进,不跳天,不跨层乱做。</li>
<li>完成后回到原始 Markdown把 TODO、阻塞、交接更新回文档。</li>
</ol>
</section>
<section class="card tone-warm">
<h3>人工开发与验收视角</h3>
<ol class="list">
<li>先看每一天的“今日定位”,知道这一天到底产出什么。</li>
<li>再看“今天必须产出的东西”和“验收快照”,确认完成标准。</li>
<li>最后跳转到对应 Markdown逐条执行或验收。</li>
<li>如果发现跨天阻塞,优先回前一天补地基,而不是在当前天临时兜底。</li>
</ol>
</section>
</div>
<div class="section-kicker">Three Layers</div>
<h2 class="section-title">文档结构一眼看清</h2>
<div class="grid three">
<section class="card">
<h3>1. 周计划路线图</h3>
<p>定义每天的大方向、交付物和验收门槛。用于排期、对齐和验收。核心入口是 <code>MASTER_TODO.md</code> 和 Day 1 到 Day 7 daily 文档。</p>
<div class="card-links">
<a class="link-chip" href="../agent%20week%20plan/00_README.md">00_README</a>
<a class="link-chip" href="../agent%20week%20plan/MASTER_TODO.md">MASTER_TODO</a>
</div>
</section>
<section class="card">
<h3>2. 每日执行清单</h3>
<p>每天的开发目标已经拆到对应 daily 文档中的详细执行清单,直接覆盖模型、字段、接口、服务、前端、测试和验收证据。</p>
<div class="card-links">
<a class="link-chip" href="../agent%20week%20plan/00_README.md">00_README</a>
<a class="link-chip" href="../agent%20week%20plan/MASTER_TODO.md">MASTER_TODO</a>
</div>
</section>
<section class="card">
<h3>3. 架构依据</h3>
<p>提供为什么要这么做、协议怎么定、权限和审计边界是什么。它不直接当 TODO但所有实现都要受它约束。</p>
<div class="card-links">
<a class="link-chip" href="../agent%20plan/01_overall_architecture.md">总体架构</a>
<a class="link-chip" href="../agent%20plan/02_semantic_ontology.md">语义本体</a>
<a class="link-chip" href="../agent%20plan/09_observability_and_trace.md">观测与 Trace</a>
</div>
</section>
</div>
<div class="section-kicker">Seven Days</div>
<h2 class="section-title">7 天总览</h2>
<div class="grid two">
<section class="card tone-olive">
<h3>Day 1 基础模型与工程骨架</h3>
<p><strong>当前状态:</strong>已完成2026-05-11。先把 Agent 资产、版本、审核、运行日志、审计日志,以及报销 / 应收 / 应付的最小业务数据来源定下来。后面所有能力都站在这一天的模型上。</p>
<div class="card-links">
<a class="link-chip" href="./day-1.html">打开日视图</a>
<a class="link-chip" href="../agent%20week%20plan/day_1_foundation_models.md">周计划</a>
<a class="link-chip" href="../agent%20week%20plan/day_1_foundation_models.md">合并文档</a>
</div>
</section>
<section class="card tone-teal">
<h3>Day 2 任务规则中心联调</h3>
<p>把规则、技能、MCP、任务从静态 UI 拉到真实后端数据。重点是规则 Markdown、版本切换、审核和上线拦截。</p>
<div class="card-links">
<a class="link-chip" href="./day-2.html">打开日视图</a>
<a class="link-chip" href="../agent%20week%20plan/day_2_rule_center_integration.md">周计划</a>
<a class="link-chip" href="../agent%20week%20plan/day_2_rule_center_integration.md">合并文档</a>
</div>
</section>
<section class="card tone-warm">
<h3>Day 3 语义本体 MVP</h3>
<p>建立 8 字段语义解析协议,让报销、应收、应付、知识查询进入同一结构,给 Orchestrator、User Agent、Hermes 统一消费。</p>
<div class="card-links">
<a class="link-chip" href="./day-3.html">打开日视图</a>
<a class="link-chip" href="../agent%20week%20plan/day_3_semantic_ontology_mvp.md">周计划</a>
<a class="link-chip" href="../agent%20week%20plan/day_3_semantic_ontology_mvp.md">合并文档</a>
</div>
</section>
<section class="card">
<h3>Day 4 Orchestrator 运行时</h3>
<p>把用户消息和定时任务统一接到 Orchestrator完成 run_id、权限拦截、Agent 路由、ToolCall 和 Trace。</p>
<div class="card-links">
<a class="link-chip" href="./day-4.html">打开日视图</a>
<a class="link-chip" href="../agent%20week%20plan/day_4_orchestrator_runtime.md">周计划</a>
<a class="link-chip" href="../agent%20week%20plan/day_4_orchestrator_runtime.md">合并文档</a>
</div>
</section>
<section class="card tone-teal">
<h3>Day 5 User Agent MVP</h3>
<p>面向用户的问答和流程辅助层。做查询、解释、规则引用、草稿生成,但严格不碰自动审批、自动付款和自动上线。</p>
<div class="card-links">
<a class="link-chip" href="./day-5.html">打开日视图</a>
<a class="link-chip" href="../agent%20week%20plan/day_5_user_agent_mvp.md">周计划</a>
<a class="link-chip" href="../agent%20week%20plan/day_5_user_agent_mvp.md">合并文档</a>
</div>
</section>
<section class="card tone-olive">
<h3>Day 6 Hermes MVP</h3>
<p>后台数字员工层。做任务触发、风险巡检、日报统计、OCR Mock、知识候选、规则草稿结果都必须可追溯。</p>
<div class="card-links">
<a class="link-chip" href="./day-6.html">打开日视图</a>
<a class="link-chip" href="../agent%20week%20plan/day_6_hermes_mvp.md">周计划</a>
<a class="link-chip" href="../agent%20week%20plan/day_6_hermes_mvp.md">合并文档</a>
</div>
</section>
<section class="card tone-accent">
<h3>Day 7 加固、演示和验收</h3>
<p>不再大扩功能只做回归、权限边界、审计、Trace、测试、演示脚本和交接收口让整周产出可跑、可演示、可继续接手。</p>
<div class="card-links">
<a class="link-chip" href="./day-7.html">打开日视图</a>
<a class="link-chip" href="../agent%20week%20plan/day_7_hardening_demo_acceptance.md">周计划</a>
<a class="link-chip" href="../agent%20week%20plan/day_7_hardening_demo_acceptance.md">合并文档</a>
</div>
</section>
</div>
<div class="section-kicker">Dependency Chain</div>
<h2 class="section-title">跨天依赖链</h2>
<div class="timeline">
<div class="timeline-step"><strong>Day 1</strong>模型、审计、运行日志、最小业务数据源</div>
<div class="timeline-step"><strong>Day 2</strong>把 Day 1 的资产 API 接进规则中心 UI</div>
<div class="timeline-step"><strong>Day 3</strong>在 Day 1/2 基础上产出统一语义结构</div>
<div class="timeline-step"><strong>Day 4</strong>用 Day 3 的语义结果完成路由与权限</div>
<div class="timeline-step"><strong>Day 5</strong>接入 User Agent 问答、解释和草稿</div>
<div class="timeline-step"><strong>Day 6</strong>接入 Hermes 任务、巡检和知识/规则候选</div>
<div class="timeline-step"><strong>Day 7</strong>统一回归、补日志、做演示和交接</div>
</div>
<div class="footer">
打开顺序建议:<a href="./day-1.html">Day 1</a><a href="./day-7.html">Day 7</a>。真正执行时,仍以原始 Markdown 为准,这套 HTML 负责加速定位和浏览。
</div>
</div>
</body>
</html>

View File

@@ -1,426 +0,0 @@
:root {
--bg: #f3ead9;
--bg-deep: #e7d8bc;
--panel: rgba(255, 250, 241, 0.9);
--panel-strong: #fff8ee;
--ink: #1f2a24;
--muted: #64655d;
--line: #dbc8a9;
--accent: #bb5b2c;
--accent-strong: #8d3d1b;
--accent-soft: #f4d9bf;
--teal: #20656d;
--teal-soft: #d8ecee;
--olive: #5f6b3a;
--olive-soft: #e6ecd7;
--shadow: 0 24px 60px rgba(84, 59, 30, 0.12);
--radius-xl: 28px;
--radius-lg: 20px;
--radius-md: 14px;
--max: 1240px;
}
* {
box-sizing: border-box;
}
html {
scroll-behavior: smooth;
}
body {
margin: 0;
font-family: "Trebuchet MS", "Gill Sans", "Lucida Grande", sans-serif;
color: var(--ink);
background:
radial-gradient(circle at top left, rgba(32, 101, 109, 0.14), transparent 26%),
radial-gradient(circle at top right, rgba(187, 91, 44, 0.15), transparent 30%),
linear-gradient(180deg, #f8f0e2 0%, var(--bg) 40%, #efe2cb 100%);
}
a {
color: inherit;
}
.shell {
width: min(100% - 40px, var(--max));
margin: 0 auto;
padding: 28px 0 56px;
}
.topbar {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
flex-wrap: wrap;
margin-bottom: 18px;
}
.brand {
display: inline-flex;
align-items: center;
gap: 12px;
text-decoration: none;
font-weight: 700;
letter-spacing: 0.04em;
text-transform: uppercase;
color: var(--accent-strong);
}
.brand-mark {
display: inline-flex;
align-items: center;
justify-content: center;
width: 42px;
height: 42px;
border-radius: 50%;
background: linear-gradient(135deg, var(--accent), #df9a44);
color: #fff7ef;
box-shadow: 0 14px 30px rgba(187, 91, 44, 0.28);
}
.quick-links,
.day-nav {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.pill {
display: inline-flex;
align-items: center;
justify-content: center;
min-height: 38px;
padding: 10px 14px;
border-radius: 999px;
border: 1px solid rgba(143, 114, 74, 0.22);
background: rgba(255, 248, 238, 0.75);
text-decoration: none;
color: var(--muted);
font-size: 14px;
transition: transform 180ms ease, border-color 180ms ease, background 180ms ease;
}
.pill:hover,
.pill:focus-visible {
transform: translateY(-1px);
border-color: rgba(187, 91, 44, 0.4);
background: rgba(255, 251, 245, 0.96);
outline: none;
}
.pill.active {
color: #fff6ef;
border-color: transparent;
background: linear-gradient(135deg, var(--accent-strong), var(--accent));
box-shadow: 0 14px 24px rgba(141, 61, 27, 0.24);
}
.hero {
position: relative;
overflow: hidden;
margin-bottom: 22px;
padding: 30px;
border: 1px solid rgba(128, 109, 82, 0.18);
border-radius: var(--radius-xl);
background:
linear-gradient(135deg, rgba(255, 248, 238, 0.95), rgba(247, 236, 216, 0.88)),
var(--panel);
box-shadow: var(--shadow);
}
.hero::after {
content: "";
position: absolute;
right: -50px;
top: -50px;
width: 220px;
height: 220px;
border-radius: 50%;
background: radial-gradient(circle, rgba(32, 101, 109, 0.16), transparent 68%);
}
.hero-badge {
display: inline-flex;
align-items: center;
gap: 8px;
margin-bottom: 12px;
padding: 7px 12px;
border-radius: 999px;
background: var(--accent-soft);
color: var(--accent-strong);
font-size: 13px;
font-weight: 700;
letter-spacing: 0.05em;
text-transform: uppercase;
}
.hero h1 {
margin: 0;
font-family: "Iowan Old Style", "Palatino Linotype", "Book Antiqua", serif;
font-size: clamp(34px, 5vw, 62px);
line-height: 1.03;
}
.hero p {
max-width: 880px;
margin: 14px 0 0;
color: var(--muted);
font-size: 18px;
line-height: 1.65;
}
.hero-meta {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 14px;
margin-top: 20px;
}
.meta-card {
padding: 14px 16px;
border-radius: var(--radius-md);
background: rgba(255, 255, 255, 0.55);
border: 1px solid rgba(132, 109, 83, 0.16);
}
.meta-label {
margin-bottom: 6px;
color: var(--muted);
font-size: 12px;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
}
.meta-value {
font-size: 16px;
line-height: 1.45;
}
.grid {
display: grid;
gap: 18px;
}
.grid.two {
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
}
.grid.three {
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
}
.card {
padding: 22px;
border: 1px solid rgba(132, 109, 83, 0.15);
border-radius: var(--radius-lg);
background: var(--panel);
box-shadow: 0 16px 36px rgba(78, 58, 32, 0.08);
animation: rise 420ms ease both;
}
.card:nth-child(2) { animation-delay: 60ms; }
.card:nth-child(3) { animation-delay: 120ms; }
.card:nth-child(4) { animation-delay: 180ms; }
.card:nth-child(5) { animation-delay: 240ms; }
.card h2,
.card h3 {
margin: 0 0 10px;
font-family: "Iowan Old Style", "Palatino Linotype", "Book Antiqua", serif;
}
.card h2 {
font-size: 28px;
}
.card h3 {
font-size: 22px;
}
.card p {
margin: 0;
color: var(--muted);
line-height: 1.7;
}
.section-title {
margin: 28px 0 14px;
font-family: "Iowan Old Style", "Palatino Linotype", "Book Antiqua", serif;
font-size: 28px;
}
.section-kicker {
margin: 30px 0 8px;
color: var(--accent-strong);
font-size: 13px;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
}
.list,
.compact-list {
margin: 12px 0 0;
padding-left: 18px;
color: var(--ink);
line-height: 1.72;
}
.compact-list {
font-size: 15px;
}
.list li + li,
.compact-list li + li {
margin-top: 8px;
}
.card-links {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-top: 16px;
}
.link-chip {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 10px 13px;
border-radius: 999px;
background: rgba(255, 255, 255, 0.76);
border: 1px solid rgba(132, 109, 83, 0.18);
text-decoration: none;
font-size: 14px;
}
.tone-warm {
background: linear-gradient(180deg, rgba(244, 217, 191, 0.55), rgba(255, 250, 241, 0.9));
}
.tone-teal {
background: linear-gradient(180deg, rgba(216, 236, 238, 0.76), rgba(255, 250, 241, 0.92));
}
.tone-olive {
background: linear-gradient(180deg, rgba(230, 236, 215, 0.82), rgba(255, 250, 241, 0.92));
}
.tone-accent {
background: linear-gradient(160deg, rgba(141, 61, 27, 0.94), rgba(187, 91, 44, 0.92));
color: #fff8f1;
}
.tone-accent p,
.tone-accent .meta-label,
.tone-accent .meta-value,
.tone-accent li {
color: rgba(255, 248, 241, 0.92);
}
.tone-accent .link-chip,
.tone-accent .pill {
background: rgba(255, 255, 255, 0.14);
border-color: rgba(255, 255, 255, 0.18);
color: #fff8f1;
}
.timeline {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 12px;
}
.timeline-step {
position: relative;
padding: 16px;
border-radius: var(--radius-md);
border: 1px solid rgba(132, 109, 83, 0.16);
background: rgba(255, 252, 247, 0.84);
}
.timeline-step strong {
display: block;
margin-bottom: 8px;
font-size: 15px;
}
.footer {
margin-top: 26px;
padding: 20px 4px 0;
color: var(--muted);
font-size: 14px;
}
.muted {
color: var(--muted);
}
.table-like {
display: grid;
gap: 12px;
}
.row {
display: grid;
grid-template-columns: minmax(120px, 0.9fr) minmax(0, 2.3fr);
gap: 14px;
padding: 14px 16px;
border-radius: var(--radius-md);
border: 1px solid rgba(132, 109, 83, 0.15);
background: rgba(255, 255, 255, 0.56);
}
.row-label {
font-size: 13px;
font-weight: 700;
letter-spacing: 0.06em;
text-transform: uppercase;
color: var(--accent-strong);
}
.row-value {
line-height: 1.68;
}
code {
padding: 1px 6px;
border-radius: 8px;
background: rgba(32, 101, 109, 0.08);
color: var(--teal);
font-family: "Lucida Console", "Courier New", monospace;
font-size: 0.92em;
}
@keyframes rise {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@media (max-width: 760px) {
.shell {
width: min(100% - 24px, var(--max));
padding-top: 18px;
}
.hero {
padding: 22px;
}
.hero p {
font-size: 16px;
}
.row {
grid-template-columns: 1fr;
}
}

View File

@@ -0,0 +1,144 @@
# 附件自动关联后台任务方案
## 背景
小财管家 AI 模式里,用户上传票据后会先做 OCR。当前附件自动关联报销草稿的后半段仍依赖前端会话内存
- 前端保留浏览器里的 `File` 对象。
- 前端在当前会话里完成草稿匹配。
- 用户点击“确认自动关联”后,再用这些 `File` 上传到报销单明细。
这会带来一个核心问题:用户发送消息后,如果刷新页面、切换会话或退出当前会话,浏览器内存里的附件原件会丢失,历史消息中的关联动作就无法继续执行。
票据夹已经能持久化 OCR 结果和源文件,并且 OCR 返回里已经带有 `receipt_id`。所以正式方案应该把“附件关联”从前端内存任务调整为后端可查询任务。
## 目标
1. 用户一上传附件即触发 OCR附件卡片显示“识别中”识别完成后显示“当前附件已识别”。
2. 用户点击发送后,前端不再依赖 `File` 原件做后续归集,而是把 OCR 产生的 `receipt_id` 提交给后端。
3. 后端创建附件关联任务,并在后台继续匹配、复制票据夹源文件、关联报销单明细。
4. 用户退出或刷新当前会话后,前端可通过保存下来的 `job_id` 查询任务状态并更新消息。
5. 如果匹配失败、置信度不足或找不到可编辑草稿,系统给出清晰提示,引导用户补充说明、上传附件或新建草稿。
## 非目标
第一版不承诺后端服务进程重启后任务状态仍可恢复。
本次实现使用轻量内存任务池,解决“用户离开前端会话导致连接断开”的问题。后续如果要做到服务重启、横向扩容、任务审计都可恢复,再新增数据库任务表。
## 核心流程
```text
用户上传票据
→ 前端立即调用 OCR
→ OCR 写入票据夹并返回 receipt_id
→ 附件卡片显示“当前附件已识别”
→ 用户点击发送
→ 前端 POST 创建附件关联任务
→ 后端后台任务继续运行
→ 前端轮询 job_id
→ 成功:消息显示已关联,并刷新报销单详情
→ 失败:消息显示失败原因和下一步动作
```
## 后端设计
### API
新增接口:
- `POST /api/v1/reimbursements/attachment-association-jobs`
- `GET /api/v1/reimbursements/attachment-association-jobs/{job_id}`
创建任务请求只传持久化引用,不传浏览器文件:
```json
{
"receipt_ids": ["receipt-1", "receipt-2"],
"prompt": "请帮我处理已上传的附件。",
"conversation_id": "inline-xxx"
}
```
状态返回:
```json
{
"job_id": "job-xxx",
"status": "running",
"message": "正在匹配可关联的报销草稿...",
"receipt_ids": ["receipt-1", "receipt-2"],
"claim_id": "",
"claim_no": "",
"uploaded_count": 0,
"skipped_count": 0,
"error": ""
}
```
状态枚举:
- `queued`:任务已创建,等待后台执行。
- `running`:正在匹配和归集。
- `succeeded`:已完成自动归集。
- `failed`:无法自动完成,返回可读错误。
### 任务执行
后端任务执行步骤:
1.`receipt_ids` 读取票据夹明细和源文件。
2. 从票据 OCR 文本、结构化字段、日期、城市提取匹配信号。
3. 查询当前用户可见且可编辑的报销草稿,排除申请单和已归档单据。
4. 对候选草稿按日期、城市、事由、草稿状态评分。
5. 置信度足够时选择目标草稿。
6. 为每份票据找到可用费用明细,没有合适明细时创建空明细。
7. 从票据夹源文件复制到报销单附件目录,并沿用 `source_receipt_id` 回填 OCR 信息。
8. 更新票据夹状态为 `linked`
9. 写入任务最终状态。
## 前端设计
### 会话消息
AI 消息需要持久化 `attachmentAssociationJob`
```json
{
"jobId": "job-xxx",
"status": "running",
"receiptIds": ["receipt-1", "receipt-2"]
}
```
这样历史会话恢复后,不再需要浏览器里的 `File` 对象,只要消息里仍有 `jobId`,就可以继续查询后端状态。
### 发送行为
当用户上传附件并点击发送:
1. 前端确认 OCR 已完成。
2. 从 OCR 结果里提取 `receipt_id`
3. 创建后端任务。
4. 立即持久化带 `job_id` 的 pending 消息。
5. 页面仍打开时轮询任务状态。
6. 页面恢复或打开历史会话时,对未完成任务继续轮询。
## 异常处理
- 未完成 OCR禁止发送提示“附件 OCR 识别中,请稍等,识别完成后再继续对话。”
- OCR 失败:禁止发送,提示“请先移除识别失败的附件或重新上传。”
- 没有 `receipt_id`:提示“当前附件没有持久化票据记录,请重新上传后再试。”
- 没有可编辑草稿:任务失败,提示用户先新建或选择草稿。
- 多个候选置信度接近:第一版不自动归集,提示补充说明或手动选择。
- 服务重启导致内存任务丢失:返回任务不存在,前端提示“后台任务状态已失效,请重新发送附件关联请求。”
## 验收标准
1. 上传附件后必须先进入 OCR 识别中状态,识别完成前不能发送对话。
2. 发送附件关联请求后,前端能收到并保存 `job_id`
3. 用户离开当前会话后,后端任务仍会继续执行。
4. 用户回到历史会话后,前端可以根据 `job_id` 查询并更新最终状态。
5. 成功后报销单明细出现附件,票据夹状态变为已关联。
6. 找不到草稿、低置信度、源文件缺失时,消息能给出明确原因。

View File

@@ -0,0 +1,22 @@
# 附件自动关联后台任务 TODO
- [x] 梳理当前前端内存任务断链原因。
- [x] 明确第一版边界:页面/会话退出可恢复,服务进程重启暂不承诺恢复。
- [x] 新增后端任务 schema。
- [x] 新增后端后台任务服务。
- [x] 新增任务创建和查询接口。
- [x] 补后端任务测试。
- [x] 新增前端任务 service。
- [x] 调整 AI 模式附件关联流程为创建后端任务。
- [x] 持久化消息里的 `attachmentAssociationJob`
- [x] 历史会话恢复时继续轮询未完成任务。
- [x] 更新前端源码断言测试。
- [x] 容器内运行后端定向测试。
- [x] 运行前端定向测试和构建。
## 验证记录
- `docker exec -w /app -e SERVER_VENV_DIR=/tmp/x-financial-server-venv x-financial-local-linux /tmp/x-financial-server-venv/bin/pytest -q server/tests/test_attachment_association_jobs.py server/tests/test_ocr_endpoints.py server/tests/test_reimbursement_endpoints.py::test_claim_item_attachment_upload_preview_and_delete server/tests/test_openapi_schema.py`
- `node --test web/tests/workbench-ai-mode-switch.test.mjs web/tests/ai-attachment-association-model.test.mjs`
- `npm --prefix web run build`
- 已重启 `x-financial-local-linux`,并确认 `/api/v1/reimbursements/attachment-association-jobs/not-exist` 返回自定义任务失效提示。

View File

@@ -1,44 +0,0 @@
# Backend API Swagger 文档
本目录用于沉淀后端接口的 Swagger / OpenAPI 产物,给开发、联调和后续 Agent 接口调用统一对照。
## 目录说明
- `openapi.json`
- 由 FastAPI `app.openapi()` 导出的完整 OpenAPI 规范。
- `interface_inventory.md`
- 基于 OpenAPI 自动整理的接口清单,按 tag 分组查看方法、路径和摘要。
## 在线入口
- Swagger UI`/docs`
- ReDoc`/redoc`
- OpenAPI JSON`/openapi.json`
如果本地默认端口不变,完整地址通常是:
- `http://127.0.0.1:8000/docs`
- `http://127.0.0.1:8000/redoc`
- `http://127.0.0.1:8000/openapi.json`
## 重新生成
`/app/server` 下执行:
```bash
PYTHONPATH=/app/server/src /app/server/.venv/bin/python /app/server/scripts/export_openapi.py
```
## 当前约定
- 全部业务接口前缀:`/api/v1`
- 知识库接口使用请求头模拟登录用户:
- `X-Auth-Username`
- `X-Auth-Name`
- `X-Auth-Role-Codes`
- `X-Auth-Is-Admin`
- Agent 资产写接口支持审计头:
- `X-Actor`
- `X-Request-Id`
- Hermes 运行时模型接口使用:
- `Authorization: Bearer <HERMES_AGENT_SHARED_TOKEN>`

View File

@@ -1,100 +0,0 @@
# Backend API Interface Inventory
- Generated at: `2026-05-11 04:14:05 UTC`
- API title: `X-Financial`
- API version: `0.1.0`
- Total paths: `28`
## Tag Overview
### agent-assets
| Method | Path | Summary |
| --- | --- | --- |
| `GET` | `/api/v1/agent-assets` | 查询 Agent 资产列表 |
| `POST` | `/api/v1/agent-assets` | 创建 Agent 资产 |
| `GET` | `/api/v1/agent-assets/{asset_id}` | 读取 Agent 资产详情 |
| `PATCH` | `/api/v1/agent-assets/{asset_id}` | 更新 Agent 资产 |
| `POST` | `/api/v1/agent-assets/{asset_id}/activate` | 激活资产当前版本 |
| `POST` | `/api/v1/agent-assets/{asset_id}/reviews` | 创建资产审核记录 |
| `GET` | `/api/v1/agent-assets/{asset_id}/versions` | 查询资产版本列表 |
| `POST` | `/api/v1/agent-assets/{asset_id}/versions` | 创建资产版本 |
### agent-runs
| Method | Path | Summary |
| --- | --- | --- |
| `GET` | `/api/v1/agent-runs` | 查询 Agent 运行日志 |
| `GET` | `/api/v1/agent-runs/{run_id}` | 读取单次 Agent 运行详情 |
### audit-logs
| Method | Path | Summary |
| --- | --- | --- |
| `GET` | `/api/v1/audit-logs` | 查询审计日志 |
### auth
| Method | Path | Summary |
| --- | --- | --- |
| `POST` | `/api/v1/auth/login` | 用户登录 |
### bootstrap
| Method | Path | Summary |
| --- | --- | --- |
| `GET` | `/api/v1/bootstrap` | 读取初始化状态 |
| `POST` | `/api/v1/bootstrap` | 写入初始化配置 |
### employees
| Method | Path | Summary |
| --- | --- | --- |
| `GET` | `/api/v1/employees` | 查询员工列表 |
| `POST` | `/api/v1/employees` | 创建员工 |
| `GET` | `/api/v1/employees/meta` | 读取员工目录元数据 |
| `GET` | `/api/v1/employees/{employee_id}` | 读取员工详情 |
| `PATCH` | `/api/v1/employees/{employee_id}` | 更新员工 |
| `POST` | `/api/v1/employees/{employee_id}/disable` | 停用员工 |
### health
| Method | Path | Summary |
| --- | --- | --- |
| `GET` | `/api/v1/health` | 服务健康检查 |
### knowledge
| Method | Path | Summary |
| --- | --- | --- |
| `POST` | `/api/v1/knowledge/documents` | 上传知识库文档 |
| `DELETE` | `/api/v1/knowledge/documents/{document_id}` | 删除知识库文档 |
| `GET` | `/api/v1/knowledge/documents/{document_id}` | 读取知识库文档详情 |
| `GET` | `/api/v1/knowledge/documents/{document_id}/content` | 下载或预览知识库原文 |
| `GET` | `/api/v1/knowledge/documents/{document_id}/onlyoffice-config` | 读取 ONLYOFFICE 预览配置 |
| `POST` | `/api/v1/knowledge/documents/{document_id}/onlyoffice/callback` | 接收 ONLYOFFICE 回调 |
| `GET` | `/api/v1/knowledge/documents/{document_id}/onlyoffice/content` | 读取 ONLYOFFICE 文档源文件 |
| `GET` | `/api/v1/knowledge/library` | 查询知识库目录 |
### reimbursements
| Method | Path | Summary |
| --- | --- | --- |
| `GET` | `/api/v1/reimbursements` | 查询报销申请列表 |
| `POST` | `/api/v1/reimbursements` | 创建报销申请 |
| `GET` | `/api/v1/reimbursements/{request_id}` | 读取报销申请详情 |
### root
| Method | Path | Summary |
| --- | --- | --- |
| `GET` | `/` | 服务根检查 |
### settings
| Method | Path | Summary |
| --- | --- | --- |
| `GET` | `/api/v1/settings` | 读取系统设置 |
| `PUT` | `/api/v1/settings` | 保存系统设置 |
| `POST` | `/api/v1/settings/model-connectivity` | 测试模型连通性 |
| `GET` | `/api/v1/settings/runtime-models/{slot}` | 读取 Hermes 运行时模型配置 |

File diff suppressed because it is too large Load Diff

View File

@@ -1,60 +0,0 @@
# 预算中心 MASTER TODO
## 总目标
把预算从首页静态展示升级为真实费控底座,让费用申请和报销都必须经过预算口径校验。
## 状态图
```text
预算额度
-> 申请提交: 预占
-> 申请退回/撤回/驳回: 释放
-> 申请通过: 保持预占
-> 报销提交: 校验申请与预算
-> 报销审批通过: 核销
-> 报销退回/撤回: 释放或回滚
```
## 总 TODO
- [ ] 新增预算中心开发文档并纳入每日核对。
- [ ] 定义预算维度:部门、成本中心、项目、费用科目、期间。
- [ ] 定义预算模型:预算额度、预算交易、预算占用。
- [ ] 定义预算状态:正常、预警、超预算、冻结。
- [ ] 定义预算交易类型:初始化、调整、预占、释放、核销、回滚。
- [ ] 新增预算列表接口。
- [ ] 新增预算详情接口。
- [ ] 新增预算台账接口。
- [ ] 新增预算占用接口或内部服务。
- [ ] 新增预算释放接口或内部服务。
- [ ] 新增预算核销接口或内部服务。
- [ ] 费用申请提交时写入预算预占。
- [ ] 费用申请驳回、撤回、取消时释放预算。
- [ ] 费用申请转报销时保留预算来源。
- [ ] 报销提交时校验预算归属和可用余额。
- [ ] 报销审批通过时核销预算。
- [ ] 报销退回时回滚预算状态。
- [ ] 报销详情展示预算占用和核销信息。
- [ ] 申请详情展示预算占用和剩余额度。
- [ ] 预算中心页面展示执行率、已占用、已核销、可用余额。
- [ ] 预算台账展示每笔来源单据和交易类型。
- [ ] 首页预算执行率改为后端真实数据。
- [ ] 本体识别支持预算维度字段。
- [ ] AI对话能解释预算不足、预算归属缺失、超预算原因。
- [ ] 添加后端单元测试。
- [ ] 添加前端预算视图测试。
- [ ] 添加申请到报销的端到端预算验收场景。
## 验收场景
- [ ] 有预算时,费用申请提交成功并预占预算。
- [ ] 预算不足时,申请提交被阻断或进入超预算复核。
- [ ] 申请驳回后,预算预占被释放。
- [ ] 申请审批通过后,预算仍保持预占。
- [ ] 申请转报销后,报销单继承预算来源。
- [ ] 报销审批通过后,预算从预占转为核销。
- [ ] 报销退回后,预算核销回滚。
- [ ] 预算中心能看到完整交易台账。
- [ ] 首页预算执行率与预算中心汇总一致。

View File

@@ -1,58 +0,0 @@
# 预算中心开发总览
## 目标
预算中心先作为费控平台的前置底座建设,优先打通:
```text
预算编制 -> 预算可用额度 -> 费用申请预占 -> 报销核销 -> 释放/调整 -> 预算看板
```
第一版不追求完整预算编制系统,而是先让申请、报销、审批、付款、归档都有真实预算口径。
## 当前项目基础
- 员工和组织已有 `cost_center` 成本中心字段,可作为预算归属维度。
- 报销单已有部门、项目、费用类型、金额、状态等字段,可接入预算核销。
- 首页已有静态预算执行率展示,但还不是后端真实预算数据。
- 费用申请已有前端意图识别和申请草稿痕迹,但预算占用还没有真实台账。
## 第一版预算中心范围
必须做:
- 预算主体:部门、成本中心、项目、费用科目。
- 预算期间:月度、季度、年度。
- 预算额度:总额、已占用、已核销、已释放、可用余额。
- 预算台账:每一次占用、核销、释放、调整都落账。
- 申请联动:费用申请提交时预占预算,驳回/撤回时释放。
- 报销联动:报销提交或审批通过时核销预算。
- 风险拦截:预算不足、超预算、缺预算归属时阻断或进入复核。
- 预算中心页面:列表、详情、台账、执行率、异常预算。
暂缓:
- 完整预算编制审批流。
- 多版本预算测算。
- 外部 ERP 预算接口。
- 真正多币种预算。
- 复杂滚动预算和预测模型。
## 关键原则
- 预算中心是独立业务域,不塞进报销 Service。
- 所有预算变化必须通过预算交易台账记录。
- 不直接改写已用金额,必须由交易汇总得到。
- 申请、报销、付款只是预算事件来源。
- 预算不足的判断必须来自后端,不依赖前端显示。
## 7天开发路径
- Day 1预算模型、状态机、接口契约。
- Day 2预算中心页面、列表、详情、台账视图。
- Day 3预算占用/释放/核销服务。
- Day 4费用申请与报销联动预算。
- Day 5审批、付款、归档中的预算状态传递。
- Day 6预算看板、本体识别、AI提示。
- Day 7端到端验收、演示数据、测试补齐。

View File

@@ -1,105 +0,0 @@
# Day 1 - 预算模型与接口契约
## 目标
先把预算中心的数据边界和接口边界定稳,避免后续把预算逻辑散落在申请、报销、审批和付款模块里。
## 开发任务
- [ ] 新增预算模型设计。
- [ ] 新增预算交易台账设计。
- [ ] 新增预算服务边界设计。
- [ ] 新增预算接口契约。
- [ ] 新增预算状态与交易类型常量。
- [ ] 明确申请、报销、付款对预算服务的调用点。
## 建议模型
预算额度:
```text
BudgetAllocation
- id
- budget_no
- fiscal_year
- period_type
- period_key
- department_id
- department_name
- cost_center
- project_code
- subject_code
- subject_name
- original_amount
- adjusted_amount
- status
- warning_threshold
- created_at
- updated_at
```
预算交易:
```text
BudgetTransaction
- id
- transaction_no
- allocation_id
- source_type
- source_id
- source_no
- transaction_type
- amount
- before_available_amount
- after_available_amount
- operator
- reason
- created_at
```
交易类型:
```text
init 初始化
adjust 调整
reserve 预占
release 释放
consume 核销
rollback 回滚
freeze 冻结
unfreeze 解冻
```
预算汇总字段由交易汇总得到:
```text
total_amount = original_amount + adjusted_amount
reserved_amount = reserve - release
consumed_amount = consume - rollback
available_amount = total_amount - reserved_amount - consumed_amount
```
## 接口契约
```text
GET /api/v1/budgets/allocations
POST /api/v1/budgets/allocations
GET /api/v1/budgets/allocations/{id}
GET /api/v1/budgets/allocations/{id}/transactions
POST /api/v1/budgets/allocations/{id}/adjust
POST /api/v1/budgets/check
POST /api/v1/budgets/reserve
POST /api/v1/budgets/release
POST /api/v1/budgets/consume
POST /api/v1/budgets/rollback
GET /api/v1/budgets/summary
```
## 验收
- [ ] 能创建一条部门月度预算。
- [ ] 能查询预算列表和详情。
- [ ] 能查询预算台账。
- [ ] 能根据部门、成本中心、项目、费用科目定位预算。
- [ ] 预算不足时 `check` 接口能返回明确原因。

View File

@@ -1,82 +0,0 @@
# Day 2 - 预算中心页面
## 目标
新增预算中心作为独立主菜单,让预算不再只是首页指标,而是可操作、可追踪、可解释的费控入口。
## 页面入口
主菜单建议:
```text
费用申请
报销中心
审批中心
预算中心
付款中心
归档中心
经营分析
```
## 页面结构
顶部指标:
- 预算总额
- 已预占
- 已核销
- 可用余额
- 超预算事项
- 预警预算数
列表字段:
- 预算编号
- 预算期间
- 部门
- 成本中心
- 项目
- 费用科目
- 预算总额
- 已预占
- 已核销
- 可用余额
- 执行率
- 状态
筛选条件:
- 年度
- 月份/季度
- 部门
- 成本中心
- 项目
- 费用科目
- 状态
详情页:
- 基本信息
- 执行概览
- 来源单据
- 交易台账
- 风险提示
- 调整记录
## 操作
- 新增预算
- 调整预算
- 冻结预算
- 查看台账
- 查看关联申请
- 查看关联报销
## 验收
- [ ] 预算中心能从主菜单进入。
- [ ] 列表能展示后端预算数据。
- [ ] 点击预算能进入详情。
- [ ] 详情能展示交易台账。
- [ ] 首页预算执行率能跳转到预算中心。

View File

@@ -1,55 +0,0 @@
# Day 3 - 预算占用、释放、核销服务
## 目标
把预算变化统一收敛到预算服务,申请、报销、付款都只能通过预算服务改变预算状态。
## 服务能力
预算检查:
- 校验预算归属是否存在。
- 校验预算是否被冻结。
- 校验可用余额是否充足。
- 返回超预算金额和处理建议。
预算预占:
- 用于费用申请提交。
- 写入 `reserve` 交易。
- 记录来源单据。
预算释放:
- 用于申请撤回、退回、驳回、取消。
- 写入 `release` 交易。
- 必须找到原始预占来源。
预算核销:
- 用于报销审批通过。
- 写入 `consume` 交易。
- 如果来源申请已有预占,应先释放预占或转换为核销,不能重复占用。
预算回滚:
- 用于报销退回或撤销审批。
- 写入 `rollback` 交易。
## 关键防错
- 同一来源单据不能重复预占。
- 同一报销单不能重复核销。
- 释放金额不能超过原预占金额。
- 核销金额不能超过可用余额加当前来源预占余额。
- 所有预算交易必须有来源单据和操作人。
## 验收
- [ ] 预算预占后可用余额减少。
- [ ] 预算释放后可用余额恢复。
- [ ] 预算核销后已核销金额增加。
- [ ] 重复预占会被阻断。
- [ ] 重复核销会被阻断。
- [ ] 台账能解释每一次余额变化。

View File

@@ -1,58 +0,0 @@
# Day 4 - 费用申请与报销联动预算
## 目标
让预算成为申请和报销之间的硬约束,先申请、再占用、再报销、再核销。
## 费用申请联动
提交申请时:
- 根据申请人部门、成本中心、项目、费用科目定位预算。
- 预算充足则预占。
- 预算不足则阻断或进入超预算复核。
- 申请详情展示预算占用结果。
申请退回/驳回/撤回时:
- 释放对应预算预占。
- 记录释放原因。
申请审批通过时:
- 保持预算预占。
- 允许转报销。
申请转报销时:
- 报销单继承申请预算来源。
- 报销金额默认不超过申请金额。
- 超过申请金额时进入风险提示或复核。
## 报销联动
报销提交时:
- 校验是否需要事前申请。
- 校验是否有关联已通过申请。
- 校验预算来源是否存在。
报销审批通过时:
- 将预算预占转为核销。
- 记录核销台账。
报销退回时:
- 回滚核销。
- 视状态保留或释放预占。
## 验收
- [ ] 有预算的申请提交后形成预占。
- [ ] 预算不足的申请不能直接提交。
- [ ] 驳回申请释放预算。
- [ ] 已通过申请能转报销。
- [ ] 报销审批通过后预算转核销。
- [ ] 未关联预算的报销不能绕过预算校验。

View File

@@ -1,52 +0,0 @@
# Day 5 - 审批、付款、归档中的预算口径
## 目标
预算信息不能只停留在申请和报销页面,还要贯穿审批、付款和归档。
## 审批中心
审批列表增加预算提示:
- 是否预算内
- 是否超预算
- 已预占金额
- 可用余额
- 预算归属
审批详情增加预算区块:
- 当前单据金额
- 对应预算额度
- 已预占
- 已核销
- 剩余额度
- 超预算原因
## 付款中心预留
第一版付款中心可以暂缓实现完整页面,但预算中心需要为付款预留:
- 付款来源单据
- 付款金额
- 付款状态
- 是否已核销预算
- 是否存在预算异常
## 归档中心
归档包需要包含预算信息:
- 预算归属
- 预算交易流水
- 申请预占记录
- 报销核销记录
- 超预算审批意见
## 验收
- [ ] 审批人能看到预算是否充足。
- [ ] 超预算审批能看到超额金额。
- [ ] 归档详情能看到预算台账摘要。
- [ ] 预算异常不会在付款/归档阶段丢失。

View File

@@ -1,90 +0,0 @@
# Day 6 - 预算看板、本体识别与AI解释
## 目标
让预算中心不只是数据表,还能被 AI 对话、本体识别和经营分析调用。
## 看板指标
- 本月预算总额
- 本月已预占
- 本月已核销
- 本月可用余额
- 部门预算排行
- 费用科目执行率
- 超预算事项数量
- 预算预警事项数量
## 本体字段
新增或强化字段:
```text
cost_center
project_code
budget_subject
budget_period
budget_amount
available_amount
reserved_amount
consumed_amount
over_budget
budget_warning
```
## 预算字段设计
预算中心字段分为四层,前端弹窗、预算台账、后端本体解析都必须使用同一套语义键。
### 预算主信息
- `budget_period`:预算周期,支持年度、季度、月份。
- `department`:所属部门,来自真实组织/部门数据。
- `cost_center`:成本中心,跟随部门归属。
- `budget_owner`:预算负责人。
- `budget_version`:预算版本,例如 `V1.0(初始版本)`
- `budget_status`:预算状态,第一版限定为 `编制中 / 已发布 / 已冻结`
- `budget_description`:预算说明。
### 预算明细
- `budget_subject`:预算科目,对应页面费用类型。
- `budget_subject_code`:预算科目编码,例如 `travel / office / training`
- `budget_amount`:预算金额。
- `warning_threshold`:预警线,例如 `70% / 80%`
- `control_action`:控制动作,第一版限定为 `正常 / 提醒 / 管控`
- `budget_remark`:明细备注。
### 预算执行
- `reserved_amount`:已占用/已预占金额。
- `consumed_amount`:已发生/已核销金额。
- `available_amount`:剩余可用金额。
- `budget_usage_rate`:预算执行率。
- `over_budget`:是否超预算。
- `budget_warning`:是否触发预算预警。
### 本体映射规则
- 页面字段使用驼峰变量,但提交/上下文统一映射为 snake_case 本体字段。
- 本体 `scenario=budget` 负责预算编制、预算查询、预算预警、预算占用、预算不足解释。
- 费用申请/报销仍使用 `scenario=expense`,但预算占用字段必须引用 `budget_subject / budget_period / cost_center`
- 问句中出现“预算金额、可用预算、剩余预算、预算占用、成本中心、预警线、超预算、预算不足”等词,应优先识别为 `budget` 场景。
- 本体输出中,预算字段优先进入 `entities`;金额类查询同步进入 `metrics`;筛选口径进入 `constraints`
## AI解释能力
需要支持的问题:
- 这个申请为什么预算不足?
- 这个报销占用了哪个预算?
- 本月哪个部门预算快超了?
- 某个项目还剩多少预算?
- 超预算申请需要谁审批?
## 验收
- [ ] 本体能识别预算相关问题。
- [ ] AI能解释预算不足原因。
- [ ] 首页预算看板来自后端真实汇总。
- [ ] 预算中心和AI回答的金额一致。

View File

@@ -1,64 +0,0 @@
# Day 7 - 联调、测试与演示验收
## 目标
冻结新增需求,只修预算闭环缺口,确保演示链路稳定。
## 端到端验收链路
链路一:预算内申请到报销
```text
创建预算 -> 发起费用申请 -> 预占预算 -> 审批通过
-> 转报销 -> 报销审批通过 -> 核销预算 -> 归档
```
链路二:预算不足
```text
创建低额度预算 -> 发起高金额申请 -> 预算不足
-> 阻断提交或进入超预算复核 -> 审批意见留痕
```
链路三:申请驳回释放预算
```text
申请提交 -> 预算预占 -> 审批驳回 -> 预算释放 -> 台账可追溯
```
链路四:重复操作防护
```text
重复提交 / 重复审批 / 重复核销 -> 后端阻断 -> 台账不重复
```
## 测试要求
- [ ] 后端预算服务单元测试。
- [ ] 申请预算预占测试。
- [ ] 报销预算核销测试。
- [ ] 预算不足阻断测试。
- [ ] 前端预算中心列表测试。
- [ ] 前端预算详情台账测试。
- [ ] 首页预算汇总测试。
## 演示数据
至少准备:
- 一个预算充足的部门预算。
- 一个预算不足的部门预算。
- 一个项目预算。
- 一个会议培训大额预算。
- 一个已经预占的申请。
- 一个已经核销的报销。
- 一个超预算待审批事项。
## 最终验收
- [ ] 预算中心能解释每一分钱从哪里来、到哪里去。
- [ ] 费用申请不能绕过预算。
- [ ] 报销审批不能绕过预算。
- [ ] 审批、归档、看板显示同一套预算数据。
- [ ] 演示链路可连续跑通。

View File

@@ -623,6 +623,14 @@ $$
AI 协作、审批效率和审批把关默认放在运营视图或管理员视图中展示。审批详情如需展示,必须明确标注“不参与费用风险裁决”。
个人工作台的用户画像详情允许在行为雷达右上角提供视角切换,避免把不同性质的指标混成单一结论:
- `financial_risk` / 财务风险视角:默认面向普通员工画像,展示费用强度、申请节奏、差旅招待、材料完整度压力、流程压力。
- `collaboration_governance` / 协作治理视角:展示 AI 协作强度、审批效率特征、审批把关特征,用于管理员或运营人员查看系统协作和流程治理行为。
- `all_behavior` / 全部行为视角:展示全部雷达维度,满足用户查看完整操作和行为细节的需求。
切换只改变雷达图可视维度和雷达下方的行为标签过滤结果,不改变后端画像快照、上方画像标签总列表、标签证据和审批优先级分。审批详情的“风险审核画像”仍默认只展示费用审核相关维度。
## 8. 测试方案
- 单元测试:覆盖归一化、同组降级、四类画像评分、等级映射、审核建议生成。

View File

@@ -142,3 +142,12 @@ docker exec x-financial-main bash -lc "cd /app && timeout 60s npm --prefix web r
- [x] 新增前端构建或组件测试,确认标签和雷达图在正常态、空态、低样本态下展示稳定。[CONCEPT: 前端展示] 证据:`npm --prefix web run build` 通过。
- [x] 后端验证在 Docker 容器执行,命令设置 60s 超时。[CONCEPT: 测试方案] 证据:`pytest ... -q` 结果 `9 passed in 6.20s`Ruff `All checks passed!`
- [ ] 前端验证通过后补充截图或交互验证说明,并回勾阶段 9 未完成项。[CONCEPT: 指标与验收]
## 阶段 12个人画像雷达视角切换
- [x]`CONCEPT.md` 补充个人画像详情的雷达视角切换契约,明确财务风险、协作治理、全部行为三档。[CONCEPT: 行为雷达图] 证据:`CONCEPT.md` 7.10 已补充三档视角和边界。
- [x] 在个人工作台画像 view model 中定义雷达视角分组和默认视角规则普通员工默认财务风险admin/仅 AI 账号默认协作治理。[CONCEPT: 行为雷达图] 证据:`employeeProfileViewModel.js` 新增 `USER_PROFILE_RADAR_VIEW_OPTIONS``resolveUserProfileDefaultRadarView()`
- [x]`ExpenseProfileDetailModal.vue` 的行为雷达标题右上角增加小型下拉切换,复用 Element Plus 控件。[CONCEPT: 前端展示] 证据:弹窗使用 `ElSelect` / `ElOption` 渲染雷达视角下拉。
- [x] 切换雷达视角时过滤展示维度和雷达下方行为标签,不改变上方画像标签、核心指标和最近操作列表。[CONCEPT: 权限和边界] 证据:`filterUserProfileRadarDimensions()``filterUserProfileTagsByRadarView()` 仅作用于雷达区入参。
- [x] 保持审批详情 `EmployeeProfileRiskCard.vue` 不混入协作治理维度。[CONCEPT: 审批详情卡片] 证据:本次未修改审批详情风险卡片。
- [x] 运行前端构建,并用浏览器确认个人画像详情的三档切换可用、空态稳定。[CONCEPT: 测试方案] 证据:`npm --prefix web run build` 通过;浏览器验证默认财务风险,可切换协作治理和全部行为,图表高度 360px底部行为标签随视角过滤。

View File

@@ -1,5 +1,11 @@
# 财务规则表补齐开发记录
## 2026-06-05 口径调整
用户明确要求业务招待费超过 500 元、大额办公用品以及金额超过 2000 元的费用申请审批要求进入财务规则中心。因此新增《公司费用申请审批规则》作为申请前置和审批阈值的财务规则依据;风险规则负责引用该财务规则并执行命中判断。
本次调整不恢复旧的单项《业务招待费报销规则》或《办公用品费报销规则》,而是使用统一规则表维护申请审批阈值,避免规则中心再次出现多个口径型规则表。
## 目标
财务规则中心只维护真正具备制度标准、且需要按职级/职务或明确人均标准执行的规则表。没有实际金额分档的费用类型,不在财务规则中心单独生成 Excel 表;其额度控制进入预算中心,申请前置和材料完整性进入风险规则。

View File

@@ -1,5 +1,9 @@
# 风险规则补齐开发记录
## 2026-06-05 口径调整
业务招待费超过 500 元、办公用品超过 2000 元、通用费用超过 2000 元的申请前置要求,制度依据统一改为财务规则《公司费用申请审批规则》。风险规则继续承担执行判断,但 `finance_rule_code` 统一指向 `expense.preapproval.policy`
## 目标
补齐预算、申请前置、报销偏差、费用标准、材料完整性类风险规则,让后续 demo 数据可以形成“预算-申请-报销-风控”的闭环。

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,91 @@
# 公开竞品资料校准与自有算法映射
更新日期2026-05-30
## 资料边界
本文件只使用公开资料做产品能力和方法论校准,不推断竞品内部算法实现。
X-Financial 的落地实现必须以自有数据、本体、规则中心、风险观察池、反馈池、
决策追踪和可回放测试为准。
公开资料来源:
- [用友 YonBIP 财务云智能费控服务白皮书](https://mks.yybip.com/group1/M00/07/EB/CgoRC2JVTMGAPdWmAEdtt5GGOf0756.pdf)
- [用友数智化财务资料:商旅费控、事项法会计与 AI 能力](https://mks.yybip.com/group1/M00/0A/29/CgoRC2XvFQuAKvNtACX8GJS9Zgo009.pdf)
- [合思 AI 财务审核专家](https://www.ekuaibao.com/aifinancialapproval.html)
- [合思 AI 审核解决方案](https://www.ekuaibao.com/solutionsr/check.html)
- [合思企业内控解决方案](https://www.ekuaibao.com/solutionsr/control.html)
## 用友公开资料校准
### 端到端费控链路
公开资料覆盖事前申请、商旅预订、智能识票、自动报账、移动审批、智能收单、
智能审核、自动核算、结算、分析、电子归档等环节。
X-Financial 映射:
-`ObjectCentricEvent` 建立申请、预订、报销、审批、付款、归档、复盘事件。
-`RiskObservation` 承接每个阶段产生的风险结论。
-`RiskDataLineage` 记录每条结论引用的单据、票据、规则、本体和 AgentRun。
### 规则模板、预算刚柔控制、信用抽审、商旅推荐
公开资料中可借鉴的能力包括规则引擎/规则模板、预算事前事中控制、刚性/柔性
控制、信用管理与抽审规则,以及基于出发时间、目的地、差旅标准和多供应商比价
的商旅推荐。
X-Financial 映射:
- `PolicyTemplateLibrary`:把制度条款沉淀为按场景、本体实体、费用类型和角色
绑定的规则模板族。
- `PreControlRecommender`:在提交前给出预算、差标、商旅供应商、住宿和交通
标准建议。
- `RiskSamplingPlanner`:结合风险分、员工画像、信用等级、历史误报率和反馈
标签,生成抽审策略、阈值和回放桶。
- `ProfileBaselineUpdater`:定期更新员工、部门、供应商、费用类型基线,为信用
抽审和预算柔性控制提供自有画像数据。
## 合思公开资料校准
### AI 审核与人机共审
公开资料强调 AI 先完成规则型检查、风险标记和建议输出,再由财务处理异常、
灰区和制度优化。X-Financial 不应让 AI 直接替代规则中心,而应把 AI 产出转成
可解释、可审计、可回放的风险观察。
X-Financial 映射:
- `HumanInLoopAutomationGate`:按置信度、风险等级、证据来源数、历史误报率和
数据质量决定自动放行、辅助、人工复核或候选观察。
- `DecisionTrace`:保留输入、命中行、贡献项、不确定性原因和解释模板。
- `RiskObservationFeedback`:把确认、误报、忽略、补件、升级、候选规则来源
转为闭环样本。
### 多凭证校验与时空推理
公开资料中,多凭证校验覆盖报销单、发票、水单、订单、小票、合同、行程等材料;
时空校验覆盖消费时间、地点、轨迹、行程逻辑和异常地点。
X-Financial 映射:
- `MultiEvidenceReconciler`:把单据、发票、附件、流水、合同、行程和事前申请
统一成证据项,输出字段一致性和缺失项。
- `SpatioTemporalRiskEngine`:基于发生时间、提交时间、明细时间、地点、行程、
开票地点和供应商地点构造时空一致性信号。
- `RiskDataQualityGate`:证据不足或字段缺失时封顶风险分,避免低质量数据触发
强结论。
## 转成 X-Financial 自有壁垒
竞品资料只作为能力校准。真正不可复制的部分必须沉淀在以下资产中:
1. 自有财务本体:场景、意图、实体、约束、风险信号、权限、置信度。
2. 自有对象中心事件日志:每个报销和风控过程可回放。
3. 自有画像基线:员工、部门、供应商、费用类型、规则、制度条款长期演化。
4. 自有反馈池:人工确认、误报、补件、升级和候选规则来源。
5. 自有回放集:正样本、负样本、反事实样本、噪声样本和历史误报样本。
6. 自有解释资产:证据链、制度条款、相似案例、贡献项、决策追踪和数据血缘。
因此,后续实现原则是:不复制竞品页面、术语和流程包装;只吸收公开资料中可验证
的能力方向,并转译为 X-Financial 的结构化数据、确定性算法、人工反馈和回放测试。

View File

@@ -0,0 +1,112 @@
# 风险图谱数据来源与壁垒资产清单
更新日期2026-05-30
## 风险相关数据来源
1. 报销单主表:`ExpenseClaim`
- 关键字段:`id``claim_no``employee_id``employee_name``department_id``department_name``expense_type``amount``currency``invoice_count``occurred_at``submitted_at``status``approval_stage``risk_flags_json`
- 用途:风险主体、金额基线、流程阶段、规则命中、图谱 claim 节点。
2. 报销明细:`ExpenseClaimItem`
- 关键字段:`item_id``item_type``item_amount``item_location``item_date``invoice_id`
- 用途:多凭证一致性、时空一致性、票据关系、图谱 item / invoice 节点。
3. 风险规则命中:`risk_flags_json` 与规则中心结果
- 来源:报销单已有风险标记、`RiskObservationService.upsert_platform_risk_flags()`
- 用途:`S_rule`、规则版本追溯、候选规则闭环。
4. 风险观察池:`RiskObservation`
- 关键字段:主体、单据、风险类型、风险信号、分数、等级、证据、图谱节点、图谱边、制度引用、相似案例、本体 JSON、决策追踪。
- 用途:统一风险结论、看板、详情、反馈、回放。
5. 风险观察反馈:`RiskObservationFeedback`
- 关键字段:反馈类型、动作、处理人、备注、扩展 payload。
- 用途:人工采纳、误报、忽略、处理完成、候选规则来源、回放标签。
6. 数字员工任务记录:`HermesTaskExecutionLog`
- 关键字段:任务配置、状态、开始结束时间、错误信息、执行摘要。
- 用途:风险扫描任务追溯、数字员工工作记录详情、失败原因。
7. Agent 运行记录:`AgentRun`
- 关键字段:`run_id``agent``source``task_id``ontology_json``route_json`、权限、状态、摘要、错误、起止时间。
- 用途:数字员工运行上下文、数据血缘、回放输入。
8. 工具调用记录:`AgentToolCall`
- 关键字段:工具类型、工具名称、请求、响应、状态、耗时、错误。
- 用途OCR、知识检索、规则执行、外部工具证据链。
9. 语义解析日志:`SemanticParseLog`
- 关键字段:原始查询、场景、意图、实体、时间范围、指标、约束、风险信号、权限、置信度。
- 用途:本体到风险图谱桥接、低置信度降级、语义血缘。
10. 财务制度知识库
- 来源:知识库文档、制度归集任务、知识检索证据。
- 用途:制度条款引用、`S_policy`、风险解释、制度缺口识别。
## `/api/v1/ontology/parse` 字段与落库方式
接口请求:`OntologyParseRequest`
- `query`:自然语言问题。
- `user_id`:当前用户。
- `context_json`:角色、部门、权限上下文。
接口响应:`OntologyParseResult`
- `scenario`:业务场景。
- `intent`:用户意图。
- `entities`:实体列表,包含类型、原值、标准值、角色、置信度。
- `time_range`:时间范围。
- `metrics`:指标列表。
- `constraints`:字段约束。
- `risk_flags`:风险信号列表。
- `permission`:权限结果。
- `confidence`:整体置信度。
- `missing_slots`:缺失槽位。
- `ambiguity`:歧义说明。
- `parse_strategy`:解析策略。
- `clarification_required` / `clarification_question`:是否需要追问。
- `run_id`:关联 `AgentRun.run_id`
- `field_errors`:字段级错误。
落库方式:
- `AgentRun.ontology_json` 保存本次解析概要。
- `SemanticParseLog.entities_json` 保存实体。
- `SemanticParseLog.time_range_json` 保存时间。
- `SemanticParseLog.metrics_json` 保存指标。
- `SemanticParseLog.constraints_json` 保存约束。
- `SemanticParseLog.risk_flags_json` 保存风险信号。
- `SemanticParseLog.permission_json` 保存权限。
- `SemanticParseLog.confidence` 保存整体置信度。
## 不可复制壁垒资产
1. 专有财务本体
- 由场景、意图、实体、约束、风险信号、权限和置信度构成。
- 价值:把自然语言、规则中心和风险图谱统一到同一业务语义。
2. 对象中心财务事件日志
-`ObjectCentricEvent` 承载,统一申请、报销、票据、审批、退回、付款、归档、复盘。
- 价值:形成可回放过程挖掘资产。
3. 风险观察反馈池
-`RiskObservationFeedback` 承载,记录确认、误报、忽略、改写、补件、升级和候选规则来源。
- 价值:把人工判断变成模型和规则迭代样本。
4. 人机共审行为数据
- 来源AgentRun、ToolCall、反馈、数字员工执行日志。
- 价值:记录谁在何时基于什么证据做了什么判断。
5. 可回放评测资产
-`AlgorithmReplaySet``RiskEvaluationCase` 承载。
- 价值:每次规则、本体或算法升级后都能复跑历史样本,防止误报率失控。
6. 实体标准化资产
-`FinancialEntityResolver``CanonicalEntityRegistry` 承载。
- 价值:沉淀供应商、商户、酒店、银行户名、员工姓名等标准主体。
7. 可解释决策资产
-`DecisionTrace`、贡献项、不确定性原因、数据血缘承载。
- 价值:让每个风险结论都能被审计、复核和反事实推演。

View File

@@ -0,0 +1,158 @@
# 数字员工财务行为图谱风险算法开发 TODO
更新日期2026-05-30
## 1. 调研与契约
- [x] 梳理现有风险相关数据来源报销单、费用明细、票据、审批记录、规则命中、AgentRun、ToolCall、语义解析日志。[CONCEPT: 背景与问题] 证据:`RISK_SOURCE_AND_MOAT.md` 已记录 `ExpenseClaim``ExpenseClaimItem``RiskObservation``RiskObservationFeedback``HermesTaskExecutionLog``AgentRun``AgentToolCall``SemanticParseLog` 和知识库来源。
- [x] 梳理现有数字员工技能和工作记录模型,确认员工技能详情、工作记录详情、知识制度记录详情的边界。[CONCEPT: 非目标] 证据:`DigitalEmployeesView.vue` 保持员工技能/工作记录页签,`DigitalEmployeeWorkRecords.vue` 负责完整详情页,`AuditDigitalEmployeeDetail.vue` 不引入知识图谱组件。
- [x] 梳理分析看板现有数据来源和页面结构,确认风险看板作为独立页签的接入方式。[CONCEPT: 分析看板风险看板] 证据:`TopBar.vue` 的分析看板下拉已新增 `risk``OverviewView.vue` 已按 `dashboard=risk` 渲染独立风险看板。
- [x] 定义 `RiskObservation` 后端字段、状态枚举、来源枚举和 JSON 字段结构。[CONCEPT: 统一风险观察模型] 证据:`server/src/app/models/risk_observation.py``server/src/app/schemas/risk_observation.py` 已实现。
- [x] 定义图谱节点和边的最小字段,不急于引入图数据库。[CONCEPT: 实体图谱层] 证据:`RiskGraphNode.as_dict()` 输出 `canonical_key/canonical_id/ontology_parse_id/ontology_version``RiskGraphEdge.as_dict()` 输出 `source/evidence/metadata`,后端算法测试已覆盖。
- [x] 定义单据详情风险证据链响应结构。[CONCEPT: API 契约建议] 证据:`riskObservations.js` 已归一单据风险观察字段,详情组件读取 `/risk-observations/claim/{claim_id}`
- [x] 定义风险看板聚合响应结构。[CONCEPT: API 契约建议] 证据:`RiskObservationDashboardRead` 已输出总览、分布、确认率、误报率和近期高风险记录。
- [x] 定义数字员工工作记录关联风险观察响应结构。[CONCEPT: API 契约建议] 证据:`/api/v1/risk-observations/execution-log/{execution_log_id}` 已按执行日志返回观察列表。
- [x] 明确不可复制壁垒资产清单:专有本体、对象中心事件日志、风险观察反馈池、人机共审行为数据、可回放评测资产。[CONCEPT: 不可复制壁垒设计] 证据:`RISK_SOURCE_AND_MOAT.md` 已明确专有本体、对象中心事件日志、风险观察反馈池、人机共审行为、可回放评测、实体标准化和可解释决策资产。
### 1.1 公开竞品资料校准
- [x] 复核用友公开资料中的端到端费控链路,确认 X-Financial 是否需要覆盖事前申请、商旅预订、报销提交、审批、付款、归档各阶段。[CONCEPT: 公开竞品资料借鉴] 证据:`PUBLIC_COMPETITOR_REFERENCE.md` 已记录用友公开资料中的事前申请、商旅预订、报销、审批、结算、分析和归档链路,并映射到 `ObjectCentricEvent``RiskObservation``RiskDataLineage`
- [x] 复核用友公开资料中的规则模板、预算刚柔控制、信用抽审和商旅推荐能力,映射为 `PolicyTemplateLibrary``PreControlRecommender``RiskSamplingPlanner`。[CONCEPT: 用友费用可借鉴模式] 证据:`PUBLIC_COMPETITOR_REFERENCE.md` 已将规则模板、预算刚柔控制、信用抽审和商旅推荐映射为 `PolicyTemplateLibrary``PreControlRecommender``RiskSamplingPlanner``ProfileBaselineUpdater`
- [x] 复核合思公开资料中的 AI 审核、人机共审、多凭证校验、时空推理和低置信度转人工能力,映射为 `MultiEvidenceReconciler``SpatioTemporalRiskEngine``HumanInLoopAutomationGate`。[CONCEPT: 合思费控可借鉴模式] 证据:`PUBLIC_COMPETITOR_REFERENCE.md` 已将合思公开资料中的 AI 审核、人机共审、多凭证和时空校验映射为 `HumanInLoopAutomationGate``DecisionTrace``MultiEvidenceReconciler``SpatioTemporalRiskEngine``RiskDataQualityGate`
- [x] 明确竞品资料只作为产品能力和方法论参考,不能作为内部算法实现依据。[CONCEPT: 资料边界] 证据:`PUBLIC_COMPETITOR_REFERENCE.md` 已写明只使用公开资料做产品能力和方法论校准,不推断竞品内部算法实现。
- [x] 把竞品借鉴项转成 X-Financial 自有数据、可解释算法、可审计证据和可回放测试,不直接复制竞品页面或术语。[CONCEPT: 对当前方案的补强] 证据:`PUBLIC_COMPETITOR_REFERENCE.md` 已把竞品能力转译为自有财务本体、对象中心事件日志、画像基线、反馈池、回放集和解释资产。
### 1.2 本体与风险图谱桥接
- [x] 梳理现有 `/api/v1/ontology/parse``SemanticParseLog``scenario``intent``entities``risk_flags``missing_slots` 的当前字段和落库方式。[CONCEPT: 本体与风险图谱桥接] 证据:`RISK_SOURCE_AND_MOAT.md` 已记录 `OntologyParseRequest/OntologyParseResult` 字段,以及 `AgentRun.ontology_json``SemanticParseLog.*_json` 落库方式。
- [x] 定义本体输出进入风险图谱的最小协议:`ontology_parse_id``ontology_version``domain``scenario``intent``entities``constraints``risk_signals``confidence`。[CONCEPT: 本体与风险图谱桥接] 证据:`OntologyRiskGraphMapping` 保留协议字段,`map_ontology_to_risk_graph()` 将本体结果转为图谱节点、边和标准风险信号。
- [x] 定义本体实体到图谱节点的映射表,例如 `expense_type -> expense_type``document_type -> invoice / expense_claim``risk_signal -> risk_observation / risk_signal`。[CONCEPT: 本体与风险图谱桥接] 证据:`ONTOLOGY_NODE_TYPE_MAP` 已归一本体实体类型,测试断言 `employee` 进入 `employee:e001` 标准节点。
- [x] 定义图谱边白名单,禁止数字员工自由创造运行时边类型。[CONCEPT: 本体与风险图谱桥接] 证据:`ALLOWED_EDGE_TYPES``ALLOWED_ONTOLOGY_EDGE_TYPES` 双层白名单已生效,测试断言本体边类型只来自白名单。
- [x] 定义风险信号标准词典,把“住宿超标 / 酒店超标 / 差旅住宿异常”等近义说法归一到同一个 `risk_signal`。[CONCEPT: 本体与风险图谱桥接] 证据:`SIGNAL_ALIASES``normalize_risk_signals()` 已归一规则、本体、图谱信号,测试断言 `city_mismatch` 归一为 `location_mismatch`
- [x] 定义本体置信度降级策略,决定自动规则匹配、半自动复核和候选观察的边界。[CONCEPT: 本体与风险图谱桥接] 证据:`_gate_from_confidence()` 输出 `automatic/review/candidate_only`,低置信度测试断言 `gate == "candidate_only"`
## 2. 数据模型
- [x] 新增风险观察模型和迁移脚本,包含主体、分数、等级、证据、来源、算法版本和反馈状态。[CONCEPT: 统一风险观察模型] 证据:`RiskObservationService.ensure_storage_ready()` 按当前项目模式运行时建表,模型包含主体、分数、证据、来源、版本和反馈状态。
- [x] 新增图谱节点存储模型或兼容结构,第一版支持员工、部门、供应商、票据、单据、制度条款、规则、风险观察。[CONCEPT: 实体图谱层] 证据:`RiskObservation.graph_node_keys_json` 已保存观察关联节点键,算法结果保留完整节点契约。
- [x] 新增图谱边存储模型或兼容结构,支持提交、包含、使用票据、关联供应商、命中规则、关联制度、相似案例等关系。[CONCEPT: 实体图谱层] 证据:`RiskObservation.graph_edge_keys_json` 已保存观察关联边键,算法图谱边包含白名单边类型。
- [x] 为图谱节点补充 `ontology_type``canonical_key``canonical_id``ontology_parse_id``ontology_version` 字段。[CONCEPT: 本体与风险图谱桥接] 证据:`RiskGraphNode` 已补齐字段,算法测试断言所有节点序列化包含 `canonical_id/ontology_parse_id/ontology_version`
- [x] 为图谱边增加白名单校验和来源字段,记录边由规则、数字员工、本体解析还是人工反馈生成。[CONCEPT: 本体与风险图谱桥接] 证据:算法图谱边通过 `ALLOWED_EDGE_TYPES` 校验,本体边通过 `ALLOWED_ONTOLOGY_EDGE_TYPES` 校验,测试断言边序列化包含非空 `source`
- [x] 新增人工反馈模型或扩展现有反馈表,支持确认、误报、忽略、已处理等状态。[CONCEPT: 人工反馈校准] 证据:`RiskObservationFeedback` 与反馈接口已支持确认、误报、忽略、已处理和备注。
- [x] 为风险观察补充 `control_stage``control_mode``automation_mode``confidence_score``sampling_strategy``evaluation_case_id`。[CONCEPT: 对当前方案的补强] 证据:`RiskObservation` 已通过兼容属性暴露 `sampling_strategy/evaluation_case_id`API schema 已补字段,服务测试覆盖字段读取。
- [x] 为风险观察补充 `ontology_parse_id``ontology_version``domain``scenario``intent``ontology_entities_json``risk_signals_json``canonical_subject_key`。[CONCEPT: 统一风险观察模型] 证据:`RiskObservation` 已从 `ontology_json` 暴露本体字段,`RiskObservationRead` 已输出,服务测试覆盖字段读取。
- [x] 为风险观察增加必要索引:主体、单据、风险类型、等级、状态、来源、创建时间。[CONCEPT: 技术验收] 证据:`RiskObservation.__table_args__` 与字段索引覆盖主体、单据、等级、状态、信号、来源和时间。
- [x] 设计对象中心财务事件日志模型,把申请、预算占用、票据上传、审批、退回、付款、归档、复盘统一为可回放事件。[CONCEPT: 不可复制壁垒设计] 证据:`process_mining.py` 已定义 `ObjectCentricEvent`,统一保存事件类型、发生时间、对象引用、来源、参与人和元数据,测试覆盖从报销单生成可回放事件。
- [x] 设计风险观察反馈池字段,记录人工采纳、驳回、改写、退回、补件、升级审批、误报和线索来源。[CONCEPT: 不可复制壁垒设计] 证据:`RiskObservationFeedback` 已通过兼容属性暴露 `decision/candidate_rule_source/confidence_score/escalation_target/supplement_required`,测试覆盖反馈来源元数据。
- [x] 设计算法回放集模型,绑定历史单据、本体版本、规则版本、算法版本和反馈标签。[CONCEPT: 不可复制壁垒设计] 证据:`replay.py` 已定义 `AlgorithmReplayCase/AlgorithmReplaySet/AlgorithmReplaySetBuilder`,测试覆盖从风险观察构建回放集。
## 3. 后端服务
- [x] 实现风险观察写入服务,统一接收规则、图谱、画像、数字员工产出。[CONCEPT: 总体架构] 证据:`RiskObservationService.upsert_observation()` 已接收 `RiskObservationDraft` 或 dict。
- [x] 实现单据维度风险观察查询服务。[CONCEPT: 单据详情风险证据链] 证据:`list_claim_observations()``/api/v1/risk-observations/claim/{claim_id}` 已实现。
- [x] 实现风险观察详情查询服务,返回证据链、基线、制度条款、相似案例和建议动作。[CONCEPT: API 契约建议] 证据:`get_observation()` 与详情接口返回 evidence、baseline、policy_refs、similar_case_claim_ids 和 decision_trace。
- [x] 实现风险看板聚合服务,输出总览、分布、趋势、排行和算法效果。[CONCEPT: 分析看板风险看板] 证据:`summarize_dashboard()``/api/v1/risk-observations/dashboard` 已返回总览、分布、确认率、误报率和近期高风险。
- [x] 实现数字员工运行记录关联风险观察查询服务。[CONCEPT: 数字员工工作记录详情] 证据:`list_execution_log_observations()``/execution-log/{execution_log_id}` 已实现。
- [x] 实现人工反馈写入和状态流转服务。[CONCEPT: 人工反馈校准] 证据:`create_feedback()` 已同步更新 `status``feedback_status`
- [x] 在服务层保留算法版本和来源信息,避免风险结论不可追溯。[CONCEPT: 技术验收] 证据:`RiskObservationService.upsert_observation()` 保留 `source/algorithm_version`,规则中心写入保留 `rule_version`,服务测试已断言。
## 4. 算法与图谱
- [x] 实现同类基线计算方法,支持部门、职级、费用类型、城市等级等口径。[CONCEPT: 同类基线偏离] 证据:`server/src/app/algorithem/risk_graph/engine.py``pytest --ignore=.venv-ocr312 tests\test_financial_risk_graph_algorithm.py -q` 通过。
- [x] 实现同类样本不足时的降级口径记录。[CONCEPT: 算法验收] 证据:`PeerBaseline(scope="insufficient_sample")` 与空风险测试覆盖。
- [x] 实现确定性规则命中分 `S_rule` 的映射逻辑。[CONCEPT: 风险总分] 证据:`server/src/app/algorithem/risk_graph/signals.py` 与算法测试覆盖。
- [x] 实现画像偏离分 `S_anomaly` 的计算逻辑。[CONCEPT: 同类基线偏离] 证据:金额偏离基线测试断言 `S_anomaly >= 90`
- [x] 实现图谱异常分 `S_graph` 的第一版信号累加逻辑。[CONCEPT: 图谱异常分] 证据:重复发票、拆单、频次、地点不一致、跨部门聚集信号已进入 `engine.py`
- [x] 实现制度语义相关分 `S_policy` 的占位契约,第一版可先接制度条款命中结果。[CONCEPT: 风险总分] 证据:`policy_refs_for_signal()` 已把制度约束型信号映射为 `policy.*`
- [x] 实现历史反馈分 `S_history`,基于相似案例退回率、确认率和误报率。[CONCEPT: 人工反馈校准] 证据:`RiskObservationService.build_history_stats()` 汇总确认/误报/退回反馈Hermes 扫描已把历史统计注入 `S_history`
- [x] 实现风险总分和等级计算,保证输出可解释贡献项。[CONCEPT: 风险总分] 证据:`RiskObservationDraft.contribution_scores` 输出 `S_rule/S_anomaly/S_graph/S_policy/S_history`
- [x] 实现本体到图谱的映射服务,输入本体解析结果,输出标准图谱节点和白名单边。[CONCEPT: 本体与风险图谱桥接] 证据:`server/src/app/algorithem/risk_graph/ontology.py` 与白名单边测试覆盖。
- [x] 实现风险信号归一化服务,保证规则中心、图谱引擎、风险看板使用同一 `risk_signal` 口径。[CONCEPT: 本体与风险图谱桥接] 证据:`normalize_risk_signals()` 已归一规则、本体和图谱信号。
- [x] 实现本体置信度门控,低置信度只生成候选观察,不触发强拦截。[CONCEPT: 本体与风险图谱桥接] 证据:低置信度本体映射测试断言 `gate == "candidate_only"`
- [x] 实现多凭证一致性校验,覆盖单据、发票、流水、合同、行程、事前申请之间的字段一致性。[CONCEPT: 合思费控可借鉴模式] 证据:第一版已覆盖报销单金额、费用明细金额合计、声明票据数量和实际票据数量一致性,输出 `multi_evidence` 证据源,算法测试已覆盖金额和票据数量不一致。
- [x] 实现时空一致性风险信号,覆盖时间、地点、行程、消费和开票关系。[CONCEPT: 合思费控可借鉴模式] 证据:第一版已覆盖报销发生日期、明细日期、报销地点和明细地点一致性,输出 `spatiotemporal` 证据源,算法测试已覆盖跨日期和跨地点异常。
- [x] 实现自动化门控逻辑,按置信度、风险等级、证据覆盖和历史误报率决定辅助、半自动、自动模式。[CONCEPT: 对当前方案的补强] 证据:`_resolve_automation_mode()` 输出 `assist/manual_review/semi_auto_review/auto_hold`,测试覆盖半自动模式。
- [x] 实现风险分层抽审策略,记录抽审口径、阈值和回放数据。[CONCEPT: 用友费用可借鉴模式] 证据:`sampling.py` 已实现 `RiskSamplingPlanner`,算法输出在 `decision_trace.sampling_strategy` 中保留策略、阈值、回放桶和原因,测试覆盖高风险进入 `focused_review/high_risk`
- [x] 建立风险评测样本集,包含正样本、负样本、反事实样本、噪声样本和历史误报样本。[CONCEPT: 合思费控可借鉴模式] 证据:`evaluation_cases.py` 已提供第一版可回放评测样本清单,覆盖 `positive/negative/counterfactual/noise/historical_false_positive`,算法测试断言分类完整。
### 4.1 深度算法壁垒模块
- [x] 实现对象中心事件日志构建器 `ObjectCentricProcessMiner`,把申请、报销、票据、付款、供应商、审批人等多对象事件统一沉淀。[CONCEPT: 对象中心过程挖掘] 证据:`ObjectCentricProcessMiner.build_from_claims()``build_from_dicts()` 已支持报销单快照与通用事件输入,测试覆盖 `claim_submitted/invoice_attached/risk_flagged` 等事件。
- [x] 实现流程一致性检测 `ConformanceRiskDetector`,识别跳步审批、返工循环、付款前异常和流程绕行。[CONCEPT: 对象中心过程挖掘] 证据:`ConformanceRiskDetector.detect()` 已输出 `payment_before_approval/approval_bypass/rework_loop/process_bypass`,测试覆盖四类流程异常。
- [x] 实现金融实体解析服务 `FinancialEntityResolver`,归一供应商、商户、酒店、银行户名和员工姓名。[CONCEPT: 实体解析与主数据归一] 证据:`entity_resolution.py` 已实现实体类型别名和标准主键归一,测试覆盖供应商/商户别名归一到同一 `vendor` 主体。
- [x] 实现标准实体注册表 `CanonicalEntityRegistry`,维护图谱标准主体 ID 和人工确认记录。[CONCEPT: 实体解析与主数据归一] 证据:`CanonicalEntityRegistry` 支持标准主体 upsert、别名合并和人工确认记录算法测试覆盖别名合并与 `confirmed_by`
- [x] 实现异构图特征构建器 `HeterogeneousRiskGraphFeatureBuilder`,输出元路径、中心性、团簇、邻域风险密度等特征。[CONCEPT: 异构图与时序图学习] 证据:`features.py` 已输出节点类型、边类型、元路径、度中心性、连通簇和邻域风险密度,算法测试覆盖重复发票图谱特征。
- [x] 实现时序图监控 `TemporalRiskGraphMonitor`,监控关系突增、消失、迁移和异常传播。[CONCEPT: 异构图与时序图学习] 证据:`temporal.py` 已比较前后图谱快照,输出关系新增、删除、突增、目标迁移和风险传播,算法测试覆盖边变化检测。
- [x] 实现多模型异常检测集成,组合稳健统计、孤立森林、局部离群、时间突变和周期偏离。[CONCEPT: 多模型异常检测组合] 证据:`anomaly_models.py` 已实现 `MultiModelAnomalyDetector`,组合 `robust_statistics/isolation_forest_proxy/local_outlier_factor_proxy/temporal_jump/periodic_deviation`,测试已覆盖五类信号。
- [x] 实现决策追踪 `DecisionTrace`,记录决策表输入、命中行、输出、版本和解释。[CONCEPT: 决策建模与策略即代码] 证据:`decisioning.py` 已定义 `DecisionTrace``DecisionTraceBuilder`,算法输出保留公式、算法版本、输入分、输出分、命中行和元数据,测试已断言。
- [x] 实现风险解释贡献字段 `feature_contributions_json``uncertainty_reasons_json``explanation_template_key`。[CONCEPT: 可解释与不确定性控制] 证据:`DecisionTraceBuilder` 已输出贡献项、不确定性原因和解释模板键,测试覆盖高风险贡献项与低质量封顶原因。
- [x] 实现反事实风险建议 `CounterfactualRiskAdvisor`,输出降低风险分的可执行补救动作。[CONCEPT: 因果分析与反事实建议] 证据:`counterfactual.py` 已根据规则、基线、图谱和数据质量贡献输出可执行降分动作,测试覆盖四类建议。
- [x] 实现控制效果分析 `ControlEffectAnalyzer`,评估规则、抽审策略或数字员工上线前后的风险变化。[CONCEPT: 因果分析与反事实建议] 证据:`control_effect.py` 已比较上线前后风险数量、均分、高风险率、确认率和误报率变化,测试已覆盖。
- [x] 实现风险数据血缘 `RiskDataLineage`记录风险观察使用的数据表、文档、OCR、AgentRun、规则版本和本体版本。[CONCEPT: 数据血缘与质量门禁] 证据:`lineage.py` 已定义 `RiskDataLineage` 和构建器支持数据表、文档、OCR、AgentRun、ToolCall、规则版本、本体版本、算法版本和事件来源测试已覆盖。
- [x] 实现风险数据质量门禁 `RiskDataQualityGate`,阻止低质量数据触发强风控结论。[CONCEPT: 数据血缘与质量门禁] 证据:`quality.py` 已实现必填字段和上下文质量门禁,低质量单据高分结论会封顶为 69算法测试覆盖缺失员工信息时禁止输出高风险。
## 5. 数字员工
- [x] 补充制度整理员工输出契约,确保制度条款可被风险观察引用。[CONCEPT: 数字员工能力分层] 证据:`policy_knowledge_contract.py` 已定义制度整理报告、知识条目、来源引用和 `risk_policy_refs`,技能文件已补输出要求,测试覆盖风险条款引用。
- [x] 新增或扩展风险扫描员工,扫描新增单据和异常关系并写入风险观察。[CONCEPT: 数字员工能力分层] 证据:`HermesRiskScannerService` 已接入 `evaluate_financial_risk_graph()`,并写入现有 `HermesRiskReport` 与单据风险标记。
- [x] 将风险扫描和员工画像巡检注册到数字员工的员工技能列表。[CONCEPT: 数字员工能力分层] 证据:新增 `financial-risk-graph-scanner``employee-behavior-profile-scanner` 技能包,并通过任务资产种子和补齐逻辑进入员工技能列表。
- [x] 员工技能详情的立即运行按技能类型调用真实后端任务。[CONCEPT: 数字员工能力分层] 证据:`OrchestratorExecutionEngine` 已按 `global_risk_scan``employee_behavior_profile_scan``finance_policy_knowledge_organize` 分发到真实服务。
- [x] 新增或扩展画像更新员工,定期更新员工、部门、供应商、费用类型基线。[CONCEPT: 数字员工能力分层] 证据:`ProfileBaselineUpdater` 已生成员工、部门、供应商、费用类型四类画像基线,`HermesEmployeeProfileScannerService.scan_employee_profiles()` 已返回 `baseline_summary``pytest --ignore=.venv-ocr312 tests/test_risk_graph_profile_baselines.py tests/test_hermes_employee_profile_baselines.py -q` 通过。
- [x] 新增风险线索归集员工输出,线索必须带事实、规则命中、证据来源和人工复核标记。[CONCEPT: 数字员工能力分层] 证据:数字员工任务与技能已注册为“风险线索归集”,`test_digital_employee_skill_catalog.py` 已锁定不输出候选规则或自动发布语义。
- [x] 数字员工运行完成后写入处理范围、处理数量、风险观察数量和失败原因。[CONCEPT: 数字员工工作记录详情] 证据:`HermesScheduler` 已写入风险图谱巡检摘要,失败仍沿用执行日志 `error_trace`
- [x] 确认 UI 上继续使用“数字员工 / 员工技能 / 工作记录”等业务命名,不在普通用户界面暴露内部实现名。[CONCEPT: 用户与场景] 证据:`DigitalEmployeesView.vue` 页签文案为“员工技能 / 工作记录”,普通界面未展示内部 Hermes 名称。
## 6. 前端:单据详情
- [x] 在单据详情风险说明附近新增风险证据链区块。[CONCEPT: 单据详情风险证据链] 证据:`RiskObservationEvidenceCard.vue` 已接入 `TravelRequestDetailView.vue`,按单据 `claimId` 拉取风险观察。
- [x] 展示风险结论、证据链节点、基线对比、制度条款、历史相似案例和建议动作。[CONCEPT: 单据详情风险证据链] 证据:详情证据链已展示风险分、贡献分、证据、图谱关系、基线、建议、制度引用和相似案例。
- [x] 支持点击风险观察进入风险观察详情或展开详情。[CONCEPT: 前端入口关系] 证据:`RiskObservationEvidenceCard.vue` 已支持多条风险观察点击切换当前详情,详情区包含贡献分、证据、图谱关系、基线建议、制度案例和反馈历史。
- [x] 无风险观察时不占用主流程空间。[CONCEPT: 前端测试] 证据:`RiskObservationEvidenceCard.vue` 在非加载、无错误且无观察记录时不渲染卡片。
- [x] 普通审批人只能看到当前单据相关证据,不展示无关员工长期敏感画像。[CONCEPT: 用户与场景] 证据:`RiskObservationEvidenceCard.vue` 只调用 `fetchClaimRiskObservations(claimId)``risk-observation-evidence-card.test.mjs` 断言不引入员工画像和知识图谱组件。
## 7. 前端:数字员工工作记录详情
- [x] 工作记录列表维持通用列表样式,详情点击进入完整详情页。[CONCEPT: 数字员工工作记录详情] 证据:`DigitalEmployeeWorkRecords.vue` 继续使用 `EnterpriseListPage`,点击行进入非侧栏完整详情。
- [x] 工作记录详情展示本次扫描范围、处理实体数量、风险观察数量和失败原因。[CONCEPT: 数字员工工作记录详情] 证据:`DigitalEmployeeRunProducts.vue` 展示扫描单据、风险观察、图谱节点/关系、画像快照和失败摘要。
- [x] 工作记录详情展示本次任务产出的风险观察列表。[CONCEPT: 数字员工工作记录详情] 证据:`DigitalEmployeeRunProducts.vue` 通过 `fetchRunRiskObservations()` 读取本次 Run 生成的风险观察并渲染列表。
- [x] 知识制度整理类记录展示知识制度记录图谱,员工技能详情不展示该图谱。[CONCEPT: 非目标] 证据:`node --test web/tests/risk-observation-evidence-card.test.mjs web/tests/digital-employee-work-record-products.test.mjs` 通过,覆盖员工技能详情不渲染 `KnowledgeIngestGraphView`、工作记录详情按任务类型解析产物和局部展开风险观察。
- [x] 风险扫描类记录展示小范围异常关系,不展示全量图谱。[CONCEPT: 图谱体现方式] 证据:`DigitalEmployeeRunProducts.vue` 点击风险观察后只展开当前观察的图谱节点、关系、证据和制度建议。
## 8. 前端:风险看板
- [x] 在分析看板中增加“风险看板”页签。[CONCEPT: 分析看板风险看板] 证据:分析看板下拉新增“风险看板”,并渲染 `RiskObservationDashboard.vue`
- [x] 增加风险总览卡片:新增风险数、高风险待处理数、涉及金额、已确认风险数、误报数量。[CONCEPT: 分析看板风险看板] 证据:`riskKpiMetrics` 已改为新增风险数、高风险待处理、涉及金额、已确认风险、误报数量和待复核,接口补充 `total_amount`
- [x] 增加风险分布图:部门、费用类型、风险类型、供应商、员工职级。[CONCEPT: 分析看板风险看板] 证据:`RiskObservationDashboard.vue` 新增业务维度分布区,统一读取 `department/expense_type/risk_type/supplier/employee_grade` 分布字段。
- [x] 增加风险趋势图7 天 / 30 天走势、高风险占比、处理完成率。[CONCEPT: 分析看板风险看板] 证据:`RiskDailyTrendChart.vue` 已展示风险观察与高风险趋势;风险看板时间窗口支持 7/30/90 天切换,处理完成率由闭环效果区承接。
- [x] 增加异常排行:部门、员工、供应商、规则、费用类型。[CONCEPT: 分析看板风险看板] 证据:风险观察聚合接口输出 `top_departments/top_employees/top_suppliers/top_rules/top_expense_types`,前端异常排行区已展示。
- [x] 增加算法效果:规则命中数、图谱异常命中数、人工确认率、误报率、待复核线索数。[CONCEPT: 分析看板风险看板] 证据:风险看板已展示平均风险分、人工确认数、误报样本和待复核线索口径,规则/图谱来源通过来源分布体现。
- [x] 风险看板所有数据通过风险观察聚合接口读取,不直接拼接业务散表。[CONCEPT: 技术验收] 证据:后端已提供 `/api/v1/risk-observations/dashboard` 作为统一聚合源。
## 9. 规则与反馈闭环
- [x] 规则中心执行结果写入风险观察池或与风险观察建立关联。[CONCEPT: 统一风险观察模型] 证据:`RiskObservationService.upsert_platform_risk_flags()` 已接收规则中心风险命中,报销提交预审会同步写入风险观察池。
- [x] 风险观察支持人工确认、误报、忽略、已处理等反馈。[CONCEPT: 人工反馈校准] 证据:反馈接口支持 `confirm/false_positive/ignore/resolve/comment`
- [x] 风险线索归集员工根据反馈整理待复核线索,不生成、不改写、不上线规则。[CONCEPT: 非目标] 证据:技能配置统一写入 `writes_rules=false``role_boundary``allowed_outputs`,目录测试覆盖不再注册候选规则技能名或规则优化输出格式。
- [x] 风险观察详情展示反馈历史和当前处理状态。[CONCEPT: 技术验收] 证据:详情模型保留 `status``feedback_status`,反馈历史由 `RiskObservationFeedback` 存储。
- [x] 风险看板展示人工确认率、误报率和待复核线索数量。[CONCEPT: 分析看板风险看板] 证据:聚合接口已输出 `confirmation_rate``false_positive_rate`;待复核线索口径由风险观察与人工复核状态聚合。
## 10. 测试与验证
- [x] 后端模型测试风险观察序列化、状态流转、JSON 字段兼容。[CONCEPT: 后端测试] 证据:`server/tests/test_risk_observations_service.py` 覆盖 upsert、dashboard、feedback 状态流转。
- [x] 后端算法测试:同类基线、降级口径、风险总分、图谱异常分。[CONCEPT: 算法与公式] 证据:`server/tests/test_financial_risk_graph_algorithm.py``pytest --ignore=.venv-ocr312 tests\test_financial_risk_graph_algorithm.py -q` 通过。
- [x] 后端接口测试:单据风险观察、风险观察详情、风险看板聚合、工作记录关联风险观察。[CONCEPT: API 契约建议] 证据:`pytest --ignore=.venv-ocr312 tests\test_financial_risk_graph_algorithm.py tests\test_risk_observations_service.py -q` 本地与 Docker 均 7 passed。
- [x] 前端测试:单据详情证据链展示和空状态。[CONCEPT: 前端测试] 证据:`node --test web/tests/risk-observation-evidence-card.test.mjs` 通过 3 项断言。
- [x] 前端测试:员工技能详情不显示知识制度图谱。[CONCEPT: 回归测试] 证据:`web/tests/digital-employee-work-record-products.test.mjs` 断言员工技能详情不渲染 `KnowledgeIngestGraphView`
- [x] 前端测试:工作记录详情只展示对应任务的图谱和风险观察。[CONCEPT: 回归测试] 证据:`web/tests/digital-employee-work-record-products.test.mjs` 覆盖任务类型识别、产物类型解析和风险观察局部展开。
- [x] 前端测试:风险看板筛选、趋势、排行和卡片数据一致。[CONCEPT: 前端测试] 证据:`node --test web/tests/risk-observation-dashboard.test.mjs` 通过 3 项断言,覆盖窗口筛选、趋势、排行和 KPI 数据源联动。
- [x] 在 Docker 容器中执行后端定向测试,命令形态为 `docker exec x-financial-main sh -lc "cd /app && pytest <target> -q"`,测试超时控制在 60s 内。[CONCEPT: 后端测试] 证据:`docker exec x-financial-main sh -lc "cd /app/server && python -m pytest --ignore=.venv-ocr312 tests/test_financial_risk_graph_algorithm.py tests/test_risk_observations_service.py -q"` 已通过 7 passed。
- [x] 执行前端构建验证,确认风险看板和详情变更不破坏现有页面。[CONCEPT: 前端测试] 证据:`npm.cmd run build` 已通过;`/app/overview``/api/v1/risk-observations/dashboard` 本地 HTTP 检查返回 200。
## 11. 验收
- [x] 单据详情能解释单个风险:结论、证据链、基线、制度条款、历史案例、建议动作齐全。[CONCEPT: 业务验收] 证据:`RiskObservationEvidenceCard.vue` 展示风险结论、贡献分、证据、图谱关系、基线建议、制度引用、相似案例和反馈历史;`node --test web/tests/risk-observation-evidence-card.test.mjs` 通过 3 项断言。
- [x] 数字员工工作记录能解释一次任务:范围、数量、产出、失败、风险观察齐全。[CONCEPT: 业务验收] 证据:`DigitalEmployeeRunProducts.vue` 展示扫描范围、处理数量、任务产物、失败摘要和本次风险观察;`node --test web/tests/digital-employee-work-record-products.test.mjs` 通过 4 项断言。
- [x] 风险看板能解释整体态势:总览、分布、趋势、排行、算法效果齐全。[CONCEPT: 业务验收] 证据:`RiskObservationDashboard.vue` 已包含总览 KPI、业务维度分布、趋势、信号排行、异常排行、算法闭环效果`npm.cmd run build` 通过。
- [x] 所有风险输出统一进入风险观察模型或兼容结构。[CONCEPT: 技术验收] 证据Hermes 风险扫描已调用 `RiskObservationService.upsert_observation()`
- [x] 高风险观察至少包含两类证据来源。[CONCEPT: 算法验收] 证据:`_apply_evidence_source_gate()` 对单一证据源高风险封顶为 69算法测试覆盖单源封顶和多源高风险通过。
- [x] 风险观察保留算法版本、来源、时间、反馈状态。[CONCEPT: 技术验收] 证据:`RiskObservation` 模型包含 `algorithm_version``source``created_at``updated_at``feedback_status`

File diff suppressed because it is too large Load Diff

View File

@@ -1,41 +0,0 @@
# Hermes 后台智能体架构总览
## 1. 定位与愿景
Hermes 是 X-Financial 系统中的**后台自动巡检与数据洞察中枢**。与处理实时对话的 UserAgent 不同Hermes 专注于异步、长周期、大批量的任务,核心价值在于提供事前的**深度风险挖掘**和定期的**业财洞察报告**。
## 2. 系统拓扑图
```mermaid
graph TD
subgraph 调度层
A[Cron Scheduler] -->|定时触发| B[Task Queue]
end
subgraph Hermes Agent 层
B -->|消费任务| C(Hermes Worker)
C --> D[Task Skills Router]
D --> E{RiskScanner Skill}
D --> F{ExpenseReport Skill}
D --> G{KnowledgeCheck Skill}
end
subgraph X-Financial 核心服务
E <--> H[(Expense DB)]
F <--> H
G <--> I[(LightRAG Graph/Vector)]
C <--> J[LLM Gateway / OpenAI]
C --> K[Notification Service / 企业微信]
end
```
## 3. 核心设计原则
1. **防抖与限流**:后台全量扫表时,必须分片执行,防止对主数据库造成 I/O 拥堵。
2. **幂等性保障**:每一个扫描任务和报告生成任务都应该具备唯一幂等键,避免因进程重启导致的重复发信或重复扣减信用分。
3. **隔离性**Hermes 的进程应与对外提供 API 服务的 Web Server 物理/逻辑隔离大模型限流策略Token Rate Limit应配置相互独立的账单通道。
## 4. 核心执行链路(示例:夜间风控巡检)
1. 凌晨 02:00Cron 触发 `trigger_risk_scan` 任务。
2. Worker 拉取状态为 `draft``submitted``risk_scanned=False` 的单据。
3. 将近三个月的相关人员单据聚类,构建 Context。
4. 调用大模型,寻找“拆单”、“合谋”、“时间/地点异常”等隐蔽风险。
5. 将发现的风险写入 `hermes_risk_report` 表,并标记对应单据。
6. 任务结束,更新执行日志,等待早晨财务主管查阅。

View File

@@ -1,46 +0,0 @@
# Hermes 数据库表结构设计
为了支持后台异步任务的执行和长期记忆(风险标记、执行结果归档),我们需要在数据库中增加(或扩充)以下表结构。
## 1. 任务调度与执行表
### `hermes_task_config` (定时任务配置表)
用于管理所有的后台巡检和推送任务,支持动态调整频率与开关。
- `id`: string (UUID)
- `task_type`: string (enum: `global_risk_scan`, `weekly_expense_report`, `kb_validation`...)
- `cron_expression`: string (e.g., `0 2 * * *`)
- `is_enabled`: boolean (默认 True)
- `payload_template`: jsonb (预留参数,如扫描的时间窗口、特定部门过滤条件等)
- `updated_at`: datetime
### `hermes_task_execution_log` (任务执行日志表)
记录每次任务的执行状态,便于排错与溯源。
- `id`: string (UUID)
- `config_id`: string (外键,关联 `hermes_task_config`)
- `started_at`: datetime
- `completed_at`: datetime
- `status`: string (enum: `running`, `success`, `failed`)
- `result_summary`: string (执行结果的简要说明,如“扫描了 1500 条单据,发现 12 条高危”)
- `error_trace`: text (如果失败,存储错误堆栈)
## 2. 深度分析结果表
### `hermes_risk_report` (深度风险报告表)
用于存储 LLM 找出的深层逻辑风险。
- `id`: string (UUID)
- `claim_id`: string (外键,关联存疑的主单据 `expense_claim`)
- `execution_log_id`: string (外键,由哪次扫描任务产生的)
- `risk_level`: string (enum: `low`, `medium`, `high`, `critical`)
- `risk_type`: string (enum: `split_billing` 拆单, `collusion` 合谋, `policy_violation` 违规...)
- `risk_description`: text (大模型生成的自然语言报告,如“该单据与前天提交的单据存在拆分可能...”)
- `related_claim_ids`: jsonb (存储关联的同谋/相关单据 ID 列表,提供上下文线索)
- `status`: string (enum: `pending_review` 待人工复核, `confirmed` 已确认为风险, `dismissed` 已忽略)
## 3. 现有表的平滑改造
### 修改 `employee` 表 (员工信用分预留)
- **新增字段** `compliance_score`: int (默认 100由 Hermes 动态扣减或恢复,用于风控引擎调节对该员工的抽查率和宽容度)
### 修改 `expense_claim` 表 (风控标记)
- **新增字段** `hermes_scanned_at`: datetime (记录该单据上次被 Hermes 扫描的时间,防止重复扫描)
- **新增字段** `hermes_risk_flag`: boolean (快速判断该单子是否被挂载了 `hermes_risk_report`)

View File

@@ -1,32 +0,0 @@
# 深度风险扫描模块设计 (Risk Scan Module)
## 1. 业务目标
将单点硬规则风控(如:发票大于 500 元是否合规)升级为**图谱式全局风控**。Hermes 将利用大语言模型LLM的逻辑推理能力在海量历史数据中寻找隐藏的违规模式。
## 2. 核心扫描链路
本模块将作为一个独立的 Skill 被定时任务触发。
### 第一步:数据快照聚合
- **提取目标**:拉取状态为 `draft``submitted` 且最近 30 天内活跃的报销单,同时带出相关的发票明细。
- **降维处理**:为避免超出大模型的 Token 上下文限制,必须对单据信息进行降维。仅提取:`申请人、时间、地点、商户名、金额、报销类型` 形成精简的 CSV 或 JSON Lines 格式。
### 第二步:大模型批量推理 (LLM Batch Inference)
- **风险定义植入**:通过 System Prompt 将目前财务最头疼的几类风险定义给模型(如拆单、套现、虚假连号发票)。
- **执行方式**:将数据按“同部门”或“同地域”分块 (Chunking) 喂给大模型。
- **Prompt 示例**
```markdown
你是一个内控审计 Agent。以下是某部门近半个月的报销流水清单。
请找出其中是否存在:
1. 拆单行为(同人、同地点、连日、小额累加)
2. 聚众套现行为(不同人、同偏僻餐馆、同日极高额)
如果发现风险,请输出对应的单号集合以及你的推理过程。
```
### 第三步:风险标记与处置
- 解析大模型返回的结构化 JSON。
- 对被判定的高危单据,在主库中插入 `hermes_risk_report` 记录。
- **动作反馈**:如果该单据正处于 `submitted` 状态,并且得分极高(如虚假连号发票),可以通过 X-Financial 原有接口自动注入“退回”动作,并附加大模型的分析日志。
## 3. 防抖与自我迭代
- **扫描去重**:利用 `expense_claim.hermes_scanned_at` 防止已经出具过报告的单据被重复投入分析队列。
- **人工纠偏 (Human-in-the-loop)**:当财务在前端驳回 Hermes 的风险提示即认为没问题事件将被记录。Hermes 可通过夜间的反思任务优化下一次 Prompt 中的判定容忍度。

View File

@@ -1,34 +0,0 @@
# 动态费控与洞察报告模块设计 (Expense Report Module)
## 1. 业务目标
基于海量的流水账单,定期(周/月)由 Hermes Agent 为部门管理者或财务总监自动生成具有**业务洞察力**的归因分析报告,将冷冰冰的数字转化为具有指导意义的自然语言建议。
## 2. 核心分析链路
### 第一步BI 数据聚合 (Data Aggregation)
- 借助 ORM 或底层 Data Warehouse (如有)Hermes 执行预置的聚合查询。
- **采集核心指标**
- 本期各部门总花费及环比/同比变动率。
- 各类目(如打车、机票、住宿、招待)的占比变化。
- Top 10 花费最多的商户(如特定几家酒店或订票平台)。
- 各类目超额/退回率最高的人员画像。
### 第二步:大模型归因分析 (LLM Attribution Analysis)
将硬性的聚合数据转化为结构化 Prompt让 LLM 充当“财务分析师”。
- **Prompt 示例**
```markdown
你是企业的财务总监助理,请阅读以下【本月报销聚合数据】。
请帮我撰写一份 300 字以内的执行摘要报告。
重点指出:
1. 哪个部门/哪类费用增长最快?原因可能是什么?
2. 我们的长尾开销集中在哪些商户?是否存在能够跟商户谈“协议价”的谈判空间?
```
### 第三步:多渠道报告分发 (Report Delivery)
- **生成制品**Hermes 利用代码解释器 (如有) 或 Markdown 引擎,将图表与文本融合成正式的 PDF 或长图。
- **触达渠道**
- **推送机制**:调用企微/钉钉机器人 API直接向管理者的工作台推送“上周费控简报”。
- **交互追问**:管理者收到简报卡片后,可以在对话框里直接@Hermes 追问:“详细列一下研发部上周在北京住宿的那 5 万块钱是怎么花的”Hermes 将调取缓存的报告上下文立即答复。
## 3. 商业价值落地
这项功能极大地解放了财务部的报表处理时间。通过提供前置的谈判线索(如发现某经济型酒店的高频住客其实都可以导流到协议酒店),可以给公司带来直接的差旅成本节约。

View File

@@ -1,63 +0,0 @@
# 部署与任务调度架构方案 (Deployment & Cron)
## 1. 业务诉求分析
Hermes 作为纯后台的智能体,它的执行过程长达几分钟甚至几小时。它绝不能与提供给前台 HTTP 请求的主 Web 服务混合在同一个事件循环Event Loop或同步进程中否则会导致 API 严重堵塞和超时崩溃。
因此Hermes 的部署需要进行**进程级解耦**。
## 2. 选型对比与推荐方案
### 方案 ACelery + Redis (重型/工业级标准)
- **优势**:业界最成熟的 Python 异步任务队列,支持极其复杂的 Cron 配置,原生支持任务重试、失败回调以及分布式扩展。
- **劣势**:增加系统组件(必须额外部署 Redis / RabbitMQ 容器),运维成本相对较高。
- **结论**:如果 X-Financial 后续要承载上千人的企业报销,这是**首选必经之路**。
### 方案 BAPScheduler + Background Worker (中型/轻量级)
- **优势**:直接在 Python 进程内运行,无需额外的消息队列组件。可以用一个单独的 Docker 容器运行 `python run_hermes_scheduler.py`
- **劣势**:多节点部署时难以控制并发(可能会多个节点同时执行同样的任务),需要引入基于数据库表或 Redis 的分布式锁。
- **结论**:适合初期快速跑通 MVP 的方案。
## 3. 推荐架构:基于 Redis 分布式锁的独立容器方案
结合当前现状,建议采用 **方案B 叠加 分布式锁** 的轻量微服务架构。
### 部署拓扑:
```yaml
# docker-compose.yml 示例切片
services:
x-financial-api:
build: .
command: uvicorn main:app
ports:
- "8000:8000"
x-financial-hermes:
build: .
command: python scripts/start_hermes_daemon.py
# 这个容器不暴露外部端口,纯粹在后台运行定时任务和消费队列
```
### 执行伪代码 (`start_hermes_daemon.py`)
```python
from apscheduler.schedulers.blocking import BlockingScheduler
from app.services.system_hermes import SystemHermesService
scheduler = BlockingScheduler()
hermes = SystemHermesService()
# 每天凌晨 3 点执行深度风控扫表
@scheduler.scheduled_job('cron', hour=3, minute=0)
def job_risk_scan():
# 获取分布式锁防止集群脑裂重复执行
if acquire_redis_lock("hermes:lock:risk_scan"):
try:
hermes.run_query("执行全局风控扫描技能...", skills=["global_risk_scan"])
finally:
release_redis_lock("hermes:lock:risk_scan")
if __name__ == "__main__":
scheduler.start()
```
## 4. 容灾与可观测性保障
- **日志采集**:确保 `hermes.run_query` 及其后台生成的 stdout/stderr 日志能够写入 ELK 或文件系统中,方便第二天的运维排查。
- **告警链路**:如果调度系统挂掉或者大模型连续多次返回失败状态码,必须通过 Webhook 飞书/钉钉及时告警系统管理员。

View File

@@ -850,6 +850,327 @@
text-underline-offset: 3px;
}
/* 竞品分析表格样式 */
.comp-table-wrapper {
width: 100%;
overflow-x: auto;
margin: 24px 0;
border: 1px solid var(--line);
border-radius: var(--radius);
box-shadow: var(--shadow-soft);
background: var(--surface);
}
.comp-table {
width: 100%;
border-collapse: collapse;
text-align: left;
font-size: 13px;
}
.comp-table th,
.comp-table td {
padding: 14px 16px;
border-bottom: 1px solid var(--line);
vertical-align: top;
line-height: 1.68;
}
.comp-table th {
background: var(--surface-strong);
color: var(--teal-deep);
font-weight: 900;
font-size: 13.5px;
white-space: nowrap;
}
.comp-table tr:last-child td {
border-bottom: none;
}
.comp-table tr:hover td {
background: var(--surface-soft);
}
.comp-highlight {
background: var(--teal-soft);
font-weight: 850;
color: var(--teal-deep);
}
.comp-table td ul {
margin: 0;
padding-left: 18px;
}
.comp-table td li {
margin-bottom: 4px;
}
/* 痛点方案卡片微动效与特色样式 */
.card {
transition: transform 0.22s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.22s ease, border-color 0.22s ease;
}
.card:hover {
transform: translateY(-2px);
box-shadow: var(--shadow-soft);
border-color: var(--teal);
}
.twin-sandbox-card {
grid-column: span 2;
background: linear-gradient(135deg, var(--surface) 60%, var(--teal-soft) 100%);
border: 1px solid var(--line-strong);
}
.twin-sandbox-badge {
display: inline-block;
padding: 2px 8px;
background: var(--teal-deep);
color: #fff;
font-size: 11px;
border-radius: 99px;
margin-bottom: 8px;
font-weight: 850;
}
@media (max-width: 1024px) {
.twin-sandbox-card {
grid-column: span 1;
}
}
/* 仿真沙盘交互组件样式 */
.twin-simulator-box {
margin-top: 20px;
padding: 18px;
border: 1px solid var(--line-strong);
border-radius: var(--radius);
background: rgba(15, 118, 110, 0.03);
backdrop-filter: blur(10px);
}
.twin-sim-title {
display: flex;
align-items: center;
gap: 8px;
font-size: 13px;
font-weight: 900;
color: var(--teal-deep);
margin-bottom: 14px;
border-bottom: 1px dashed var(--line);
padding-bottom: 8px;
}
.sim-dot {
width: 8px;
height: 8px;
background: var(--teal);
border-radius: 50%;
animation: pulse 1.8s infinite;
}
@keyframes pulse {
0% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(15, 118, 110, 0.5); }
70% { transform: scale(1); box-shadow: 0 0 0 6px rgba(15, 118, 110, 0); }
100% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(15, 118, 110, 0); }
}
.twin-sim-layout {
display: grid;
grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
gap: 18px;
}
.twin-sim-ctrl {
display: grid;
gap: 12px;
align-content: start;
}
.ctrl-group {
display: grid;
gap: 6px;
}
.ctrl-group label {
font-size: 12px;
font-weight: 850;
color: var(--ink-soft);
}
.ctrl-group select {
width: 100%;
height: 34px;
padding: 0 8px;
border: 1px solid var(--line);
border-radius: 6px;
background: var(--surface);
color: var(--ink);
font-size: 12.5px;
font-family: var(--font);
outline: none;
}
.ctrl-group select:focus {
border-color: var(--teal);
}
.highlight-val {
color: var(--teal-deep);
font-weight: 900;
font-family: var(--mono);
}
.ctrl-group input[type="range"] {
-webkit-appearance: none;
width: 100%;
height: 6px;
border-radius: 3px;
background: var(--line);
outline: none;
}
.ctrl-group input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 16px;
height: 16px;
border-radius: 50%;
background: var(--teal);
cursor: pointer;
border: 2px solid var(--surface);
box-shadow: 0 2px 6px rgba(15,118,110,0.3);
transition: transform 0.1s ease;
}
.ctrl-group input[type="range"]::-webkit-slider-thumb:hover {
transform: scale(1.15);
}
.range-labels {
display: flex;
justify-content: space-between;
font-size: 10px;
color: var(--muted);
margin-top: 2px;
font-family: var(--mono);
}
#run-sim-btn {
width: 100%;
height: 36px;
background: var(--teal-deep);
color: #fff;
border: none;
border-radius: 6px;
font-size: 13px;
font-weight: 900;
cursor: pointer;
box-shadow: 0 4px 12px rgba(16, 47, 43, 0.2);
transition: all 0.2s ease;
}
#run-sim-btn:hover {
background: var(--teal);
transform: translateY(-1px);
box-shadow: 0 6px 16px rgba(15, 118, 110, 0.3);
}
#run-sim-btn:active {
transform: translateY(0);
}
.twin-sim-display {
position: relative;
border: 1px solid var(--line);
border-radius: 6px;
background: var(--surface);
padding: 12px;
display: grid;
align-content: space-between;
overflow: hidden;
}
.sim-scanner {
position: absolute;
top: -100%;
left: 0;
width: 100%;
height: 12px;
background: linear-gradient(180deg, rgba(15, 118, 110, 0.2) 0%, transparent 100%);
pointer-events: none;
z-index: 2;
}
.sim-scanner.scanning {
animation: scan 1.2s ease-in-out;
}
@keyframes scan {
0% { top: -10px; }
100% { top: 100%; }
}
.metric-group {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 10px;
z-index: 1;
}
.sim-metric {
padding: 8px;
border: 1px solid var(--surface-strong);
border-radius: 6px;
background: var(--surface-soft);
display: grid;
gap: 4px;
}
.sim-metric .m-label {
font-size: 11px;
color: var(--muted);
}
.sim-metric .m-value {
font-family: var(--mono);
font-size: 16px;
font-weight: 900;
line-height: 1.1;
}
.sim-metric .m-value.teal { color: var(--teal); }
.sim-metric .m-value.orange { color: var(--amber); }
.sim-metric .m-value.red { color: var(--red); }
.sim-metric .m-value.blue { color: var(--blue); }
.sim-report-badge {
margin-top: 10px;
padding: 4px;
border-radius: 4px;
background: var(--surface-strong);
color: var(--teal-deep);
font-size: 10.5px;
font-weight: 850;
text-align: center;
transition: all 0.3s ease;
z-index: 1;
}
.sim-report-badge.success {
background: var(--teal-soft);
color: var(--teal-deep);
border: 1px solid rgba(15, 118, 110, 0.2);
}
@media (max-width: 580px) {
.twin-sim-layout {
grid-template-columns: 1fr;
}
}
@media (max-width: 1500px) {
.page {
grid-template-columns: 236px minmax(0, 1fr);
@@ -971,6 +1292,8 @@
<a href="#why"><span class="dot"></span>为什么要做</a>
<a href="#future"><span class="dot"></span>未来地位</a>
<a href="#blue"><span class="dot"></span>蓝海空间</a>
<a href="#competitor-analysis"><span class="dot"></span>竞品对比</a>
<a href="#painpoints-solution"><span class="dot"></span>痛点解决</a>
<a href="#goal"><span class="dot"></span>开发目的</a>
<a href="#algorithms"><span class="dot"></span>核心算法</a>
<a href="#modules"><span class="dot"></span>项目模块</a>
@@ -1037,28 +1360,19 @@
<h2>为什么要做智能费控平台</h2>
<p class="section-desc">
智能费控不是把报销审批电子化,而是把企业每一笔支出变成可理解、可预测、可解释的经营信号。
AI、RAG、智能体、异常检测和预算联动进入财务流程后费用平台会从“流程系统”升级为“经营控制系统”
前,在金税四期深化、数电发票单轨制全面普及的政策背景下,传统的“后置流程型”费控已被逼入死胡同,企业必须构建全链路智能费控平台
</p>
</div>
<div class="deep-copy">
<p>
第一,费用是企业经营动作最密集、最贴近一线的数据入口。销售拜访客户会产生差旅和招待,
项目交付会产生交通、住宿、外包和办公支出,培训、采购、通信、会务也都以费用形式落地。
如果企业只在报销完成后做核销,就只能看到“钱已经花了”;如果在申请、预算占用、票据上传、
审批和归档全过程做智能分析,就能提前看到“这笔钱为什么要花、是否该花、花完后对预算和风险有什么影响”。
第一,<strong>数电票时代倒逼全链路数字化</strong>。随着全国数电发票的单轨制落地发票的真伪验重、多系统抵扣、合规归档以及全生命周期的追踪已无法通过传统人工肉眼或零散的OCR识别来解决。系统必须具备在发票导入瞬间进行结构化解析、关联交易比对、业务事由交叉匹配的自动化能力实现“开票即采集、采集即验真、入账即归档”。
</p>
<p>
第二,财务工作的重心正在从人工处理转向分析、预测和决策支持。Gartner 2025 年财务 AI 调研显示,
财务组织最常见的 AI 用例已经包括知识管理、应付流程自动化、错误与异常检测McKinsey 的 CFO 调研也显示,
绝大多数受访者期待 AI 减少人工分析负担、生成洞察。这意味着费控平台必须具备自动识别、自动解释和自动沉淀的能力,
否则它会停留在“录单工具”,无法进入未来财务的核心工作台。
第二,<strong>企业从“事后核销”向“事前控制”的主动性跨越</strong>。传统ERP与报销系统核心是“记账与流程审批”当员工提交报销单时费用早已产生。智能费控利用 RAG 知识检索、预算实时联动,在费用申请阶段甚至消费发生的瞬间(如因公商旅预订)就进行预算额度校验与制度约束,使费控前置到决策端。
</p>
<p>
第三,费用风险越来越隐蔽。传统审批能挡住“缺附件”“超标准”这类显性问题,
但很难发现拆单、跨部门合谋、异常频次、预算节奏异常、同组偏离、长期材料质量差等隐性问题。
ACFE 的职业舞弊报告将虚构或夸大业务费用列为典型报销舞弊形态;随着 AI 生成票据、深度伪造和自动化攻击出现,
企业更需要一个能把票据、人员、部门、历史行为、预算和制度放在一起分析的平台。
第三,<strong>费用舞弊与异常的隐性化、复杂化</strong>。根据 ACFE 2024 年《全球职业舞弊与滥用报告》显示,全球企业中约有 15% 的舞弊案件与费用报销直接相关,且平均潜伏期长达 18 个月。传统的强硬制度配置只能拦截“超标准”、“无附件”等显性异常,但对于拆单报销、异地多点异常消费、同组偏离度过高、长期合作供应商异常开票等隐性风控,需要基于大数据画像和语义关系的图谱检测。
</p>
</div>
@@ -1122,74 +1436,66 @@
<div class="section-kicker">02 / COMPANY POSITION</div>
<h2>费控在未来公司的地位</h2>
<p class="section-desc">
未来公司的费控,会从“报销审批入口”变成“经营支出操作系统”
未来公司的费控,会从“报销审批工具”变成“企业费用智能操作系统”Expense OS
它一端连接员工和部门的真实业务动作,另一端连接预算、现金流、成本、风险、制度和管理决策。
</p>
</div>
<div class="deep-copy">
<p>
组织分工看CFO 的角色正在从财务记录者变成业务伙伴和技术治理者
Deloitte 的未来财务洞察持续强调,财务团队会把更多时间投入分析、预测和决策支持;
Deloitte APAC CFO 2025 调研也显示,接近一半 CFO 认为生成式 AI 会在两年内显著改变行业、组织和财务职能。
这意味着费控不应再被放在“报销系统”这个狭窄位置,而应该成为 CFO 获取一线经营信号的前置雷达。
<strong>组织分工与决策支持</strong>来看CFO 的角色正加速从“合规记录者”转变为“战略业务伙伴HR/IT/业务协同的中心”。Deloitte 2025 年未来财务展望报告指出,财务部门未来的工作精力将有 70% 倾斜于数据分析和未来预测。智能费控则是这一变革的第一步——通过把一线经营活动(如差旅、招待、项目交付)产生的每一笔资金流动转化为语义数据,为 CFO 的“战略驾驶舱”提供实时的一手信号
</p>
<p>
业务管理看,预算不再只是年初编制和月底复盘。未来预算需要跟每一次费用申请实时联动:
当前预算池还有多少、审批后使用率是多少、是否触达预警线、该部门同类费用是否异常、是否影响项目毛利和现金节奏。
因此费控会成为部门经理、项目负责人和财务 BP 共同使用的经营协同平台。
<strong>预算与资源控制</strong>来看,未来的预算管控不再是“年初编预算,月底对账单”的静态割裂状态。智能费控通过建立动态预算池与资金控制链,使预算能够在秒级发生响应。这保证了业务部门在项目推进过程中,能实时感知每一笔花费对项目整体毛利空间、部门现金流余量的动态影响,促使人人关注经营效果。
</p>
<p>
风险控制看,未来公司的费用风险不是单张票据能解释清楚的,而是多源数据的组合问题
一张票据可能合规,但一个人三个月内的频次、金额、地点、客户、同行人和预算占比可能异常。
智能费控要把这些信号拉成一张网,让管理者在支付之前就看到风险轮廓。
<strong>业务运营与体验</strong>来看,智能费控是消除部门隔阂、降低一线行政摩擦的“润滑剂”。当平台实现高度数字化与免报销消费结算时,员工不再需要贴票垫资,管理者不再需要在审批页面盲目点“同意”,财务不再需要枯燥审单,整个公司的运营效率将得到数量级提升
</p>
</div>
<div class="split">
<div>
<ul class="bullets">
<li><strong>经营仪表盘</strong>部门费用、项目消耗、预算占比、执行率、风险热区可以被实时汇总</li>
<li><strong>预算守门员</strong>费用申请不再只看“能不能报”,而要看“是否符合预算节奏”。</li>
<li><strong>内控前置层</strong>票据、地点、人员、金额、制度条款和历史行为被联动审核</li>
<li><strong>AI 财务工作台</strong>财务人员可以通过自然语言查询制度、解释风险、生成审批建议和费用报告</li>
<li><strong>规则与知识工厂:</strong>制度解释、规则生成、风险复盘和人工反馈进入可持续优化闭环</li>
<li><strong>管理决策入口:</strong>管理者可以询问“哪个部门预算风险最高”“哪些费用正在吞噬毛利”。</li>
<li><strong>经营支出中枢 (Expense OS)</strong> 将多系统的零散流程、差旅出行、第三方消费直接通过本体层收归统一</li>
<li><strong>预算守护雷达</strong> 在业务动作发生时实现“秒级预算占用与测算”,而不是事后核销时的“超支警告”。</li>
<li><strong>合规内控防火墙</strong> 结合发票验真、合同信息、行程轨迹和行为偏差等多模态数据对风险自动拦截</li>
<li><strong>战略决策沙盘</strong> 支持 CFO 和高管直接询问“各项目利润健康度”、“政策变动预算消耗预测”等深度命题</li>
<li><strong>自进化规则工厂:</strong> 依据历史人工审批意见和申诉结果,系统能自动推荐规则优化方案,实现制度灰度升级</li>
</ul>
</div>
<div>
<div class="flow-diagram" aria-label="费控未来地位流程图">
<div class="flow-row" style="--cols: 3">
<div class="flow-node">
<div class="flow-node-title">业务动作</div>
<div class="flow-node-text">出差、采购、招待、培训、项目交付</div>
<div class="flow-node-title">业务场景</div>
<div class="flow-node-text">差旅、招待、采购、项目外包、会务支出</div>
</div>
<div class="flow-node dark">
<div class="flow-node-title">智能费控平台</div>
<div class="flow-node-text">预算、单据、制度、票据、风险、智能体</div>
<div class="flow-node-title">费用智能操作系统</div>
<div class="flow-node-text">本体语义 · 实时预算 · 智能体 · 仿真沙盘</div>
</div>
<div class="flow-node">
<div class="flow-node-title">财务结果</div>
<div class="flow-node-text">成本、现金、核销、支付、账务沉淀</div>
<div class="flow-node-title">经营结果</div>
<div class="flow-node-text">成本优化、合规账套、税务风险减免、现金流稳健</div>
</div>
</div>
<div class="flow-row" style="--cols: 3">
<div class="flow-node blue">
<div class="flow-node-title">组织与预算</div>
<div class="flow-node-text">部门、项目、成本中心、预算池</div>
<div class="flow-node-title">CFO 战略看板</div>
<div class="flow-node-text">业财融合数据、动态毛利预警、资金利用率</div>
</div>
<div class="flow-node amber">
<div class="flow-node-title">据与画像</div>
<div class="flow-node-text">费用画像、行为画像、同组基准</div>
<div class="flow-node-title">字孪生仿真</div>
<div class="flow-node-text">制度变动测算、预算优化预测、行为偏差度</div>
</div>
<div class="flow-node blue">
<div class="flow-node-title">管理决策</div>
<div class="flow-node-text">预警、报告、经营洞察、规则优化</div>
<div class="flow-node-title">协同平台</div>
<div class="flow-node-text">免贴票、即时审批、智能助手交互</div>
</div>
</div>
</div>
<div class="diagram-caption">
费控位于经营动作和财务结果之间,未来承担预算守门、规则解释、风险识别、数据画像和管理洞察的中枢角色
智能费控平台向上承接公司战略与预算规则,向下沉入业务一线动作,最终演化为企业支出的全局操作系统
</div>
</div>
</div>
@@ -1200,45 +1506,203 @@
<div class="section-kicker">03 / BLUE OCEAN</div>
<h2>智能分析费控平台的蓝海</h2>
<p class="section-desc">
传统 ERP、OA、报销系统和财务共享平台已经覆盖了流程但对“语义理解、自动洞察、隐性风险识别、
预算占比解释、部门费用经营分析”的覆盖仍然不足。蓝海空间正来自这个空白:
市场正在从单点报销工具转向 AI 驱动的差旅、费用、发票、预算和风险一体化平台。
传统的报销系统、OA 工作流和财务共享软件已是一片红海,产品竞争停留在表单设计与流程配置层面。而真正能为企业带来颠覆性价值的“智能费控蓝海”,则存在于从流程处理到智能化决策预测的跃迁中。
</p>
</div>
<div class="deep-copy">
<p>
Grand View Research 2025 年报告预计,全球差旅与费用管理软件市场 2030 年将达到 106.9 亿美元,
2024 至 2030 年复合增速为 16.9%。更重要的是,它特别提到 AI 可用于审批与支付自动化、
员工差旅历史和支出模式分析、OCR 票据字段识别以及基于自然语言的交互。
这说明市场真正的增长点不只是“报销线上化”,而是“费用智能化”。
根据全球著名调研机构 Grand View Research 2025 发布的市场预测报告,全球差旅与费用管理T&E软件市场规模在 2030 年将达到 <strong>106.9 亿美元</strong>2024 至 2030 年的复合年增长率CAGR高达 <strong>16.9%</strong>。报告中特别强调,市场增长的核心引擎已不再是单纯的“线上化审批”,而是引入 AI Agent 进行决策自动化、基于 OCR/LLM 的隐性欺诈检测、以及基于企业历史支出行为的可持续 ESG 碳足迹追踪。这表明,“费用智能化与经营沙盘仿真”是蕴含巨大商业溢价的崭新蓝海。
</p>
</div>
<div class="grid cols-3">
<article class="card">
<strong>非结构化数据智能化</strong>
<p>票据、制度 PDF、Excel 规则、审批意见、用户自然语言都能进入同一个语义管道</p>
<strong>1. 认知与决策型 AI Agent</strong>
<p>从“机械填表和固定规则校验”跨越到“能基于上下文自主决策、异常判定、并提供人机协同解释”的财务数字员工</p>
</article>
<article class="card">
<strong>部门费用经营化</strong>
<p>费用从“报销明细”升级为“部门预算执行、费用结构、异常趋势、经营压力”的管理对象</p>
<strong>2. 财务数字孪生与政策仿真</strong>
<p>基于公司历史发票、人员组织、预算规则建立仿真模型,模拟差旅标准或预算政策调整后,对企业资金流与利润的实际影响</p>
</article>
<article class="card">
<strong>风险识别前置化</strong>
<p>拆单、超预算、重复票据、地点不一致、附件缺失、异常频次都可以更早被发现</p>
<strong>3. 多源异构数据语义对齐</strong>
<p>打破各子系统CRM、ERP、OA、商旅聚合商接口壁垒利用 Semantic Ontology 本体语义层实现业务数据的天然降维对齐</p>
</article>
<article class="card">
<strong>财务智能体运营化</strong>
<p>后台数字员工不再等待人点击,而是按周期巡检数据、生成报告和沉淀优化候选</p>
<strong>4. 行为偏离与隐性欺诈识别</strong>
<p>基于知识图谱与图机器学习技术,识别跨期拆单、虚假报销、同组偏离异常、跨部门关联交易等人工难以察觉的系统性风险</p>
</article>
<article class="card">
<strong>规则治理产品化</strong>
<p>自然语言规则、风险规则、Excel 规则和制度知识可以逐步变成可测试、可版本化资产</p>
<strong>5. 自进化规则治理闭环</strong>
<p>支持自然语言输入制度,由 LLM 自动翻译成系统执行规则,并通过人工申诉与退回反馈,在后台自动完成规则库的校准 and 修正</p>
</article>
<article class="card">
<strong>财务知识即时化</strong>
<p>RAG 与知识库让制度解释从人工翻文档,转为“问一句,返回依据和建议”</p>
<strong>6. 绿色财务与 ESG 碳足迹</strong>
<p>在费控和商旅端自动提取交通工具、酒店的排放系数,帮助企业在进行费用管控的同时,同步测算并生成企业 ESG 碳足迹报告</p>
</article>
</div>
</section>
<section class="section" id="competitor-analysis">
<div class="section-head">
<div class="section-kicker">03.1 / COMPETITORS</div>
<h2>主流费控系统竞品分析</h2>
<p class="section-desc">
要实现上述蓝海构想,必须客观分析当前市场上主流的费控软件。各大软件定位明确,但普遍在“智能化决策”、“跨系统语义融合”及“政策仿真”方面存在显著痛点。
</p>
</div>
<div class="comp-table-wrapper">
<table class="comp-table">
<thead>
<tr>
<th style="width: 14%">竞品名称</th>
<th style="width: 25%">核心定位与主要优势</th>
<th style="width: 28%">核心痛点与局限性</th>
<th style="width: 33%">X-Financial 的创新解决与差异化</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>SAP Concur</strong></td>
<td>
<ul>
<li>全球化费控天花板,支持多币种、多税制、全球财税合规。</li>
<li>商旅生态极其成熟,能够与 SAP ERP 体系深度咬合。</li>
</ul>
</td>
<td>
<ul>
<li>本土化体验被国内用户诟病(如数电发票处理缓慢)。</li>
<li>系统界面臃肿,配置与二次开发极为繁琐。</li>
<li>实施周期漫长,运维与实施费用极其高昂。</li>
</ul>
</td>
<td class="comp-highlight">
<ul>
<li>原生适配数电发票单轨制,具备开箱即用的 AI 智能验真归档。</li>
<li>基于本地化轻量级大模型架构,大幅降低实施门槛和部署成本。</li>
</ul>
</td>
</tr>
<tr>
<td><strong>分贝通</strong></td>
<td>
<ul>
<li>以商旅消费支付为切入点,打造“商旅+支付+费控”模式。</li>
<li>倡导“无需报销”体验,员工体验极佳。</li>
</ul>
</td>
<td>
<ul>
<li>强依赖平台内置的消费商城生态,在面对大量零星线下费用、外包采购时灵活性不足。</li>
<li>对于复杂的多级跨账簿预算、动态共享额度的精细化管控能力相对偏弱。</li>
</ul>
</td>
<td class="comp-highlight">
<ul>
<li>提供基于本体层屏蔽异构商城壁垒的通用解析能力,线下报销补件与线上免报销消费实现语义对齐。</li>
<li>支持复杂层级的预算池(部门/项目/成本中心)秒级动态关联管控。</li>
</ul>
</td>
</tr>
<tr>
<td><strong>合思 (易快报)</strong></td>
<td>
<ul>
<li>一站式业财收支管理,国内市占率居前。</li>
<li>生态系统对接广泛,能与国内主流 ERP 无缝打通,配置灵活。</li>
</ul>
</td>
<td>
<ul>
<li>系统逻辑依然以“传统工作流表单”为主,交互较为传统,缺乏智能助理的深度参与。</li>
<li>缺乏中长周期的员工行为偏差分析、规则误报自适应纠偏机制。</li>
</ul>
</td>
<td class="comp-highlight">
<ul>
<li>前台 User Agent 支持自然语言直接进行报销提问、草稿生成、异常核对与智能交互。</li>
<li>通过共享本体与规则中心,让财务人员可以用自然语言配置和灰度升级风控规则。</li>
</ul>
</td>
</tr>
<tr>
<td><strong>每刻报销</strong></td>
<td>
<ul>
<li>专注于大中型企业的智能财务共享,规则引擎非常强大。</li>
<li>AI 智能审单能力强,支持复杂的集团化多层级架构。</li>
</ul>
</td>
<td>
<ul>
<li>系统的学习曲线陡峭,对业务人员和普通员工的交互不够平滑。</li>
<li>侧重于既定流程的合规审计,对于预算和费控政策调整带来的前瞻性影响缺乏模拟仿真能力。</li>
</ul>
</td>
<td class="comp-highlight">
<ul>
<li>前台大模型辅助,降低普通用户填单学习曲线。</li>
<li><strong>核心差异化:首创“财务数字孪生与仿真沙盘”</strong>,在系统级测试和决策前对费控变动进行量化分析预测。</li>
</ul>
</td>
</tr>
</tbody>
</table>
</div>
</section>
<section class="section" id="painpoints-solution">
<div class="section-head">
<div class="section-kicker">03.2 / SOLUTIONS</div>
<h2>X-Financial 痛点解决方案</h2>
<p class="section-desc">
针对以上竞品普遍面临的系统孤岛、缺乏智能决策、政策调整靠经验等痛点X-Financial 提出了以 **“AI + 数字化 + 财务数字孪生”** 为核心的下一代费控解决方案。
</p>
</div>
<div class="grid cols-2">
<article class="card accent-teal">
<strong>一、 解决多系统孤岛Semantic Ontology 本体语义层</strong>
<p>
传统软件通过 API 强行硬编码对接 CRM、ERP 和商旅系统,一旦系统升级,接口极易断裂,导致业财数据“语义断层”。
</p>
<p style="margin-top: 8px; font-size: 13px;">
<strong>X-Financial 方案:</strong> 我们设计了包含 8 个关键因子的本体语义协议domain, scenario, intent 等)。无论是口语化描述、页面动作还是三方消费接口,都先被解析为统一的“本体状态”,再分发至下层服务。这实现了跨系统的语义级天然对齐,让数据真正融为一体。
</p>
</article>
<article class="card accent-blue">
<strong>二、 解决财务假智能User Agent & Hermes 双智能体闭环</strong>
<p>
市面软件仅使用 OCR 识别将文字填入表单,人工审核工作量并没有显著降低,也无法识别隐性舞弊。
</p>
<p style="margin-top: 8px; font-size: 13px;">
<strong>X-Financial 方案:</strong> 我们构建了双 Agent 循环。前台 <strong>User Agent</strong> 帮员工和财务进行友好交互,自动查漏补正,解释退回原因;后台 <strong>Hermes 数字员工</strong> 定时在数据底座扫描分析员工近90/180天的费用画像和行为画像依据同组偏差算法自动判定隐性风险出具报告。
</p>
</article>
<article class="card accent-amber">
<strong>三、 解决规则配置难LLM 驱动的规则与知识工厂</strong>
<p>
传统系统的规则引擎配置需要 IT 人员编写繁杂的条件表达式,难以响应公司制度的频繁变动。
</p>
<p style="margin-top: 8px; font-size: 13px;">
<strong>X-Financial 方案:</strong> 支持财务直接上传自然语言描述的制度文档。系统通过大模型将文本转化为可测试、可执行的规则库资产;当发生审批争议或误报时,支持财务通过“反馈池”对规则 and 知识库进行一键校正,进入自进化闭环。
</p>
</article>
<article class="card twin-sandbox-card">
<span class="twin-sandbox-badge">首创蓝海技术</span>
<strong>四、 解决政策盲目调整财务数字孪生与仿真沙盘Financial Digital Twin</strong>
<p>
很多企业在遇到经营波动时会盲目调低差旅标准如酒店降低20%),这容易导致员工满意度下降、灰色报销增多或合规偏离率升高,甚至因行政摩擦上升造成更大的隐性成本。目前市场没有任何一款软件能评估规则调整带来的实际后果。
</p>
<p style="margin-top: 8px; font-size: 13.5px;">
<strong>X-Financial 方案:</strong> 我们通过融合组织架构树、员工费用画像、预算控制规则与历史发票数据库,为企业构建了一个“财务数字孪生体”。当管理层想要修改政策(如“下调销售部酒店标准 15%”)时,可在系统<strong>仿真沙盘Simulation Sandbox</strong>中运行模拟。沙盘会模拟历史真实或合成出的数万个出差场景进行回归测算量化预测此次政策调整对“未来费用降幅预估降低11%”、“员工合规偏离率预估提升8%”、“预计审批流程摩擦时间预估提升12%)”的多维影响,为企业提供真正科学的决策辅助。
</p>
</article>
</div>
</section>
@@ -1811,6 +2275,8 @@ budget_control =
<a href="#why"><span class="dot"></span>为什么要做</a>
<a href="#future"><span class="dot"></span>未来地位</a>
<a href="#blue"><span class="dot"></span>蓝海空间</a>
<a href="#competitor-analysis"><span class="dot"></span>竞品对比</a>
<a href="#painpoints-solution"><span class="dot"></span>痛点解决</a>
<a href="#goal"><span class="dot"></span>开发目的</a>
<a href="#algorithms"><span class="dot"></span>算法能力</a>
<a href="#modules"><span class="dot"></span>模块清单</a>

View File

@@ -1,56 +0,0 @@
# Knowledge Answers TODO
更新时间2026-05-16
目标:
- 让知识库问答的主路径从“LightRAG 检索 + 慢模型二次整理”改为“结构化证据优先 + 模型可选总结”。
- 让问答能力尽量依赖当前文档内容本身,而不是依赖某一份制度、某一个城市或某一种表格写法。
- 参考 Yuxi 的优点,优先补齐 `统一解析思路 + 文档类型友好的结构增强 + 检索后原文证据回退`,不照搬其完整平台基础设施。
Yuxi 调研结论:
- [x] 已完成 Yuxi 调研与方案提炼
备注Yuxi 的通用性主要来自三层:统一文档解析、可切换的 chunk/preset、检索不足时回到解析后 Markdown 继续取证;并不是靠给某个文档写死回答逻辑。
本轮改造原则:
- [x] 先撤掉文档特化硬编码,再补通用结构能力。
- [x] 真实答案只能来自当前命中文档的内容,代码里不固化制度金额、地区档位或条款结论。
- [x] 即使问题不是表格表达,也要能基于章节、条款、列表、键值对、上下文段落给出可读答案。
- [x] 模型只负责“压缩表达”,不负责“凭空补事实”;模型超时时也必须能返回像样的证据型答复。
实施清单:
- [x] 移除当前临时文档特化 fast path
备注:删除当前围绕差旅表格、城市档位、职级档位的临时规则,避免系统继续向单文档 hardcode 演化。
- [x] 入库增强:补通用结构附录
备注:参考 Yuxi 的解析/分块思想,在现有入库文本增强中补充章节、条款、列表、键值对、表格与上下文邻接信息,让非表格关系也能被稳定命中。
- [x] 检索后增强:生成面向回答的证据片段
备注:从命中的 hits 中再次抽取更短、更结构化的 answer evidence优先保留标题路径、条款句、列表项、表格行和与 query 强相关的上下文窗口。
- [x] 回答链路重构:证据驱动直答
备注:新增通用知识问答直答器,先根据 answer evidence 生成可直接展示的短答案;只有在证据不足或问题需要更自然表达时才调用模型。
- [x] 模型总结收口:缩小上下文面,保留原文约束
备注:把传给模型的上下文从“整段命中 chunk”收缩到“高置信 answer evidence”既降延迟也降低答非所问和错列风险。
- [x] 降级回答升级:从“命中摘抄”改成“证据摘要”
备注:即使模型超时或失败,也要返回按证据组织好的结论、依据和缺失信息,而不是大段原文拼贴。
- [x] 测试补齐
备注:覆盖非表格制度文本、表格文本、列表/键值对文本、模型超时降级、去除硬编码路径等关键回归点。
- [x] 真实验证与回填 TODO
备注:已重建当前知识库索引并完成真实验证。当前“回答整理”阶段已降到亚秒级,但 LightRAG 首次/冷启动检索仍受 embedding 与 rerank 耗时影响,后续如要继续压缩总耗时,应进一步优化检索参数与模型链路。
验收标准:
- [x] 常规知识问答不再长时间卡在“正在整理答案”。
- [x] 文档不是表格表达时,仍能基于章节/条款/列表/上下文回答。
- [x] 文档内容变动后,不需要改业务代码里的制度结论或金额常量。
- [x] 模型超时时仍能返回结构清楚、证据明确的答案。
- [x] 相关测试通过,且没有破坏现有知识库问答流程。
验证记录:
- [x] 单测通过:`test_user_agent_service.py``test_knowledge_normalizer.py``test_knowledge_rag_service.py` 共 35 项全部通过。
- [x] 当前知识库文档已按新规则 `force` 重建索引成功。
- [x] 真实问答抽检:`餐补标准是什么?``费用发生后多久内提交报销申请?``前往北京出差的报销标准是什么?`
备注:回答生成阶段约 `0.24s ~ 0.30s`;其中“前往北京出差”问题会明确提示当前证据未直接给出“北京”地区档位映射,不再硬猜。

View File

@@ -1,896 +0,0 @@
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>X-Financial 轻量知识库归集与问答优化开发文档</title>
<style>
:root {
--green-900: #064e3b;
--green-700: #047857;
--green-600: #10b981;
--green-100: #dff8ec;
--green-50: #effcf6;
--blue-700: #1d4ed8;
--blue-50: #eff6ff;
--amber-600: #d97706;
--amber-50: #fffbeb;
--red-600: #dc2626;
--red-50: #fef2f2;
--ink-900: #071124;
--ink-700: #24324a;
--ink-600: #58677f;
--ink-500: #728098;
--line: #dbe5ef;
--line-strong: #c6d4e2;
--surface: #ffffff;
--surface-soft: #f7fafc;
--shadow: 0 10px 26px rgba(15, 23, 42, 0.08);
--radius: 8px;
}
* {
box-sizing: border-box;
}
html {
scroll-behavior: smooth;
}
body {
margin: 0;
background:
linear-gradient(180deg, rgba(239, 252, 246, 0.78), rgba(247, 250, 252, 0.96) 360px),
var(--surface-soft);
color: var(--ink-900);
font-family: "IBM Plex Sans", "Microsoft YaHei UI", "Microsoft YaHei", "PingFang SC", sans-serif;
line-height: 1.62;
letter-spacing: 0;
}
a {
color: inherit;
text-decoration: none;
}
code {
padding: 2px 6px;
border-radius: 6px;
background: rgba(15, 23, 42, 0.06);
color: var(--ink-700);
font-family: "JetBrains Mono", "Cascadia Code", Consolas, monospace;
font-size: 0.92em;
}
.shell {
display: grid;
grid-template-columns: 276px minmax(0, 1fr);
min-height: 100dvh;
}
.sidebar {
position: sticky;
top: 0;
align-self: start;
height: 100dvh;
padding: 28px 22px;
border-right: 1px solid var(--line);
background: rgba(255, 255, 255, 0.86);
backdrop-filter: blur(18px);
overflow: auto;
}
.brand {
display: flex;
gap: 12px;
align-items: center;
margin-bottom: 30px;
}
.logo-mark {
display: grid;
width: 42px;
height: 42px;
place-items: center;
border-radius: 8px;
background: linear-gradient(145deg, var(--green-700), var(--green-600));
color: #fff;
font-weight: 800;
box-shadow: 0 10px 18px rgba(16, 185, 129, 0.26);
}
.brand-title {
font-size: 15px;
font-weight: 800;
line-height: 1.2;
}
.brand-subtitle {
margin-top: 4px;
color: var(--ink-500);
font-size: 12px;
}
.nav-label {
margin: 22px 0 8px;
color: var(--ink-500);
font-size: 12px;
font-weight: 700;
}
.nav {
display: grid;
gap: 6px;
}
.nav a {
display: flex;
align-items: center;
min-height: 38px;
padding: 8px 10px;
border-radius: 8px;
color: var(--ink-700);
font-size: 13px;
font-weight: 650;
}
.nav a:hover {
background: var(--green-50);
color: var(--green-900);
}
.nav-dot {
width: 7px;
height: 7px;
margin-right: 10px;
border-radius: 999px;
background: var(--line-strong);
}
main {
min-width: 0;
padding: 34px 42px 56px;
}
.hero {
display: grid;
grid-template-columns: minmax(0, 1.14fr) minmax(300px, 0.86fr);
gap: 24px;
align-items: stretch;
margin-bottom: 24px;
}
.hero-panel,
.metric-panel,
section,
.card {
border: 1px solid var(--line);
border-radius: var(--radius);
background: var(--surface);
box-shadow: var(--shadow);
}
.hero-panel {
padding: 30px;
border-color: rgba(16, 185, 129, 0.28);
background:
linear-gradient(135deg, rgba(255, 255, 255, 0.96), rgba(239, 252, 246, 0.9)),
var(--surface);
}
.kicker {
display: inline-flex;
align-items: center;
min-height: 28px;
padding: 4px 10px;
border: 1px solid rgba(16, 185, 129, 0.24);
border-radius: 999px;
background: rgba(16, 185, 129, 0.1);
color: var(--green-900);
font-size: 12px;
font-weight: 800;
}
h1 {
max-width: 780px;
margin: 16px 0 14px;
font-size: 34px;
line-height: 1.18;
letter-spacing: 0;
}
.hero-copy,
.section-desc,
.card p,
.phase span,
.footnote {
color: var(--ink-600);
font-size: 14px;
}
.hero-copy {
max-width: 800px;
margin: 0;
font-size: 15px;
}
.hero-actions {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-top: 22px;
}
.pill {
display: inline-flex;
align-items: center;
min-height: 32px;
padding: 6px 11px;
border-radius: 999px;
background: #fff;
border: 1px solid var(--line);
color: var(--ink-700);
font-size: 12px;
font-weight: 750;
}
.pill.primary {
background: var(--green-700);
border-color: var(--green-700);
color: #fff;
}
.metric-panel {
display: grid;
gap: 12px;
padding: 18px;
}
.metric {
padding: 14px;
border-radius: 8px;
background: var(--surface-soft);
border: 1px solid var(--line);
}
.metric-label {
color: var(--ink-500);
font-size: 12px;
font-weight: 700;
}
.metric-value {
margin-top: 5px;
font-size: 18px;
line-height: 1.28;
font-weight: 800;
}
section {
margin-top: 18px;
padding: 24px;
}
.section-head {
display: flex;
gap: 18px;
align-items: flex-start;
justify-content: space-between;
margin-bottom: 16px;
}
.section-title {
margin: 0 0 8px;
font-size: 22px;
line-height: 1.25;
}
.section-desc {
max-width: 920px;
margin: 0;
}
.tag {
flex: 0 0 auto;
min-height: 28px;
padding: 4px 10px;
border-radius: 999px;
background: var(--green-50);
color: var(--green-900);
font-size: 12px;
font-weight: 800;
border: 1px solid rgba(16, 185, 129, 0.22);
}
.grid-2,
.grid-3,
.grid-4 {
display: grid;
gap: 14px;
}
.grid-2 {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.grid-3 {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
.grid-4 {
grid-template-columns: repeat(4, minmax(0, 1fr));
}
.card {
padding: 17px;
box-shadow: none;
}
.card h3 {
margin: 0 0 10px;
font-size: 16px;
line-height: 1.3;
}
.card p {
margin: 0;
}
.card ul,
.card ol {
margin: 0;
padding-left: 18px;
color: var(--ink-600);
font-size: 14px;
}
.card li + li {
margin-top: 7px;
}
.tone-green {
background: var(--green-50);
border-color: rgba(16, 185, 129, 0.26);
}
.tone-blue {
background: var(--blue-50);
border-color: rgba(37, 99, 235, 0.18);
}
.tone-amber {
background: var(--amber-50);
border-color: rgba(217, 119, 6, 0.2);
}
.tone-red {
background: var(--red-50);
border-color: rgba(220, 38, 38, 0.16);
}
.flow {
display: grid;
gap: 10px;
margin-top: 6px;
}
.flow-row {
display: grid;
grid-template-columns: 132px minmax(0, 1fr);
gap: 12px;
align-items: start;
padding: 12px;
border: 1px solid var(--line);
border-radius: 8px;
background: var(--surface-soft);
}
.flow-key {
color: var(--green-900);
font-size: 13px;
font-weight: 800;
}
.flow-body {
color: var(--ink-600);
font-size: 14px;
}
.diagram {
padding: 16px;
border: 1px solid var(--line);
border-radius: 8px;
background: #0f172a;
color: #e5eef8;
overflow-x: auto;
font-family: "JetBrains Mono", "Cascadia Code", Consolas, monospace;
font-size: 13px;
line-height: 1.65;
white-space: pre;
}
.timeline {
display: grid;
gap: 12px;
}
.phase {
display: grid;
grid-template-columns: 150px minmax(0, 1fr);
gap: 14px;
padding: 14px;
border: 1px solid var(--line);
border-radius: 8px;
background: var(--surface-soft);
}
.phase-key {
color: var(--green-900);
font-size: 13px;
font-weight: 850;
}
.phase-body strong {
display: block;
margin-bottom: 4px;
color: var(--ink-900);
font-size: 15px;
}
.checklist {
display: grid;
gap: 10px;
}
.check {
position: relative;
padding: 12px 12px 12px 34px;
border: 1px solid var(--line);
border-radius: 8px;
background: var(--surface-soft);
color: var(--ink-700);
font-size: 14px;
}
.check::before {
content: "";
position: absolute;
left: 13px;
top: 17px;
width: 8px;
height: 8px;
border-radius: 999px;
background: var(--green-600);
}
.link-list {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-top: 14px;
}
.link-chip {
display: inline-flex;
align-items: center;
min-height: 30px;
padding: 5px 10px;
border: 1px solid var(--line);
border-radius: 999px;
background: #fff;
color: var(--ink-700);
font-size: 12px;
font-weight: 750;
}
.link-chip:hover {
border-color: rgba(16, 185, 129, 0.5);
color: var(--green-900);
}
footer {
margin-top: 22px;
color: var(--ink-500);
font-size: 12px;
text-align: center;
}
@media (max-width: 1080px) {
.shell {
grid-template-columns: 1fr;
}
.sidebar {
position: static;
height: auto;
border-right: 0;
border-bottom: 1px solid var(--line);
}
.hero,
.grid-2,
.grid-3,
.grid-4 {
grid-template-columns: 1fr;
}
main {
padding: 24px 18px 42px;
}
}
@media (max-width: 680px) {
h1 {
font-size: 28px;
}
.section-head,
.phase,
.flow-row {
grid-template-columns: 1fr;
}
.section-head {
display: grid;
}
}
</style>
</head>
<body>
<div class="shell">
<aside class="sidebar">
<div class="brand">
<div class="logo-mark">KB</div>
<div>
<div class="brand-title">轻量知识库归集</div>
<div class="brand-subtitle">LightRAG + Hermes 优化方案</div>
</div>
</div>
<div class="nav-label">文档导航</div>
<nav class="nav">
<a href="#position"><span class="nav-dot"></span>定位与边界</a>
<a href="#architecture"><span class="nav-dot"></span>轻量架构</a>
<a href="#borrow"><span class="nav-dot"></span>Yuxi 借鉴点</a>
<a href="#modules"><span class="nav-dot"></span>模块设计</a>
<a href="#retrieval"><span class="nav-dot"></span>召回与回答</a>
<a href="#delivery"><span class="nav-dot"></span>实施路线</a>
<a href="#quality"><span class="nav-dot"></span>验收标准</a>
</nav>
<div class="nav-label">硬约束</div>
<div class="nav">
<a href="#quality"><span class="nav-dot"></span>不做重平台</a>
<a href="#quality"><span class="nav-dot"></span>证据优先回答</a>
<a href="#quality"><span class="nav-dot"></span>增量任务可追踪</a>
</div>
</aside>
<main>
<div class="hero">
<div class="hero-panel">
<span class="kicker">开发文档 · 先定边界再实现</span>
<h1>X-Financial 轻量知识库归集与问答优化方案</h1>
<p class="hero-copy">
本方案不把 X-Financial 改造成专业知识库平台,而是在现有
<code>LightRAG</code><code>Hermes</code><code>AgentRun</code>
和知识库 UI 上补齐最薄弱的归集、分块、召回和证据回答能力。
Yuxi 只作为成熟设计参考,借鉴其统一解析、分块预设和评估思想。
</p>
<div class="hero-actions">
<span class="pill primary">保留现有 LightRAG</span>
<span class="pill">轻量 Parser</span>
<span class="pill">条款级分块</span>
<span class="pill">混合召回</span>
<span class="pill">证据化回答</span>
</div>
</div>
<div class="metric-panel">
<div class="metric">
<div class="metric-label">核心目标</div>
<div class="metric-value">准、快、可解释</div>
</div>
<div class="metric">
<div class="metric-label">改造范围</div>
<div class="metric-value">归集与召回链路,不重做平台</div>
</div>
<div class="metric">
<div class="metric-label">并发预期</div>
<div class="metric-value">5-10 用户查询可降级、有上限</div>
</div>
</div>
</div>
<section id="position">
<div class="section-head">
<div>
<h2 class="section-title">定位与边界</h2>
<p class="section-desc">
知识库在 X-Financial 中是业务辅助能力,不是独立知识管理产品。
因此实现必须克制:不引入重型多租户平台,不替换现有业务数据模型,
不把知识库 UI 做成复杂后台,只补齐影响问答质量的关键薄层。
</p>
</div>
<span class="tag">轻量优先</span>
</div>
<div class="grid-3">
<div class="card tone-green">
<h3>要解决的问题</h3>
<ul>
<li>Word、PDF、Excel 等文件进入 RAG 前缺少统一结构。</li>
<li>制度类文档如果按普通 chunk 切分,条款容易被切散。</li>
<li>问答质量依赖向量召回,缺少关键词、标题、条款补召回。</li>
<li>效果优化缺少固定评测集,容易靠体感判断。</li>
</ul>
</div>
<div class="card tone-blue">
<h3>保留的现有能力</h3>
<ul>
<li><code>KnowledgeService</code> 继续负责文件库和状态入口。</li>
<li><code>KnowledgeRagService</code> 继续封装 LightRAG 查询和入库。</li>
<li><code>KnowledgeIndexTaskManager</code> 继续承接 Hermes 增量任务。</li>
<li>前端知识管理继续保持简单文件夹与文件列表形态。</li>
</ul>
</div>
<div class="card tone-amber">
<h3>明确不做</h3>
<ul>
<li>不整体引入 Yuxi 平台。</li>
<li>不把存储改成 Milvus + Neo4j。</li>
<li>不一次性接入全量 OCR 引擎。</li>
<li>不新增复杂多租户知识库后台。</li>
</ul>
</div>
</div>
</section>
<section id="architecture">
<div class="section-head">
<div>
<h2 class="section-title">轻量架构</h2>
<p class="section-desc">
新增能力只放在 LightRAG 前后两侧:前侧负责把文件变成稳定 Markdown 和业务友好 chunk
后侧负责混合召回、证据重排和可靠回答。LightRAG 仍是主召回核心。
</p>
</div>
<span class="tag">薄层增强</span>
</div>
<div class="diagram">原始文件
├── docx / pdf / xlsx / pptx / csv / txt
轻量 Parser
├── 统一 Markdown
├── 表格上下文
└── 页码 / sheet / 条款路径
Chunk Preset
├── laws制度条款
├── qa常见问答
└── table表格行组
现有 LightRAG / Qdrant
混合召回
├── LightRAG 语义召回
├── 标题与条款关键词召回
└── 轻量重排 top 3-5
证据化回答
├── 命中证据
├── 直接结论
└── 缺失信息说明</div>
</section>
<section id="borrow">
<div class="section-head">
<div>
<h2 class="section-title">Yuxi 借鉴点</h2>
<p class="section-desc">
Yuxi 的价值不在于整套平台,而在于成熟的归集分层思想:
文件先解析成 Markdown再按场景分块再索引再评估。
这些思想可以小规模落地到现有服务内。
</p>
</div>
<span class="tag">借鉴而非搬运</span>
</div>
<div class="grid-4">
<div class="card">
<h3>统一 Parser</h3>
<p>学习 Yuxi 把多格式文件统一转 Markdown 的入口设计,但只实现 X-Financial 当前需要的格式。</p>
</div>
<div class="card">
<h3>分块 Preset</h3>
<p>借鉴 RAGFlow-like preset。先做 <code>laws</code><code>qa</code><code>table</code> 三类。</p>
</div>
<div class="card">
<h3>两阶段状态</h3>
<p>内部区分解析和索引。UI 仍可显示简单归纳状态,后台记录真实失败点。</p>
</div>
<div class="card">
<h3>轻量评测</h3>
<p>不做评估平台,只维护 JSON 用例和脚本,持续检查召回与回答质量。</p>
</div>
</div>
<div class="link-list">
<a class="link-chip" href="https://github.com/xerrors/Yuxi">Yuxi README</a>
<a class="link-chip" href="https://github.com/xerrors/Yuxi/blob/main/backend/package/yuxi/plugins/parser/unified.py">Yuxi unified parser</a>
<a class="link-chip" href="https://github.com/xerrors/Yuxi/blob/main/backend/package/yuxi/knowledge/chunking/ragflow_like/presets.py">Yuxi chunk presets</a>
<a class="link-chip" href="https://github.com/xerrors/Yuxi/blob/main/backend/package/yuxi/knowledge/chunking/ragflow_like/parsers/laws.py">Yuxi laws parser</a>
</div>
</section>
<section id="modules">
<div class="section-head">
<div>
<h2 class="section-title">模块设计</h2>
<p class="section-desc">
新增模块必须小而清楚,避免把逻辑继续堆进单个 Service。
单个核心文件控制在 800 行以内,优先按解析、分块、召回、评测拆分。
</p>
</div>
<span class="tag">职责拆分</span>
</div>
<div class="flow">
<div class="flow-row">
<div class="flow-key">knowledge_parser.py</div>
<div class="flow-body">
负责把 docx、pdf、xlsx、csv、txt 等文件转成 Markdown。
输出正文、标题路径、页码、sheet、表头、解析告警。
</div>
</div>
<div class="flow-row">
<div class="flow-key">knowledge_chunking.py</div>
<div class="flow-body">
根据文件夹、文件类型和文档特征选择分块策略。
第一批只实现制度、问答、表格三类。
</div>
</div>
<div class="flow-row">
<div class="flow-key">knowledge_retrieval.py</div>
<div class="flow-body">
在 LightRAG 命中结果外补充关键词、条款标题和文件名召回。
最终输出小而准的证据块。
</div>
</div>
<div class="flow-row">
<div class="flow-key">knowledge_eval.py</div>
<div class="flow-body">
读取轻量评测用例,检查 expected 文件、关键词、证据和答案约束。
用于每次调整参数后的回归验证。
</div>
</div>
</div>
</section>
<section id="retrieval">
<div class="section-head">
<div>
<h2 class="section-title">召回与回答策略</h2>
<p class="section-desc">
目标不是让模型更会猜,而是让系统给模型更可靠的证据。
制度问题优先命中条款,表格问题保留表头与行上下文,回答必须暴露依据和缺失信息。
</p>
</div>
<span class="tag">证据优先</span>
</div>
<div class="grid-3">
<div class="card tone-green">
<h3>召回层</h3>
<ul>
<li>LightRAG 继续提供语义召回。</li>
<li>条款号、标题、文件名、关键词做补召回。</li>
<li>召回候选数量有上限,避免并发下无限扩张。</li>
</ul>
</div>
<div class="card tone-blue">
<h3>重排层</h3>
<ul>
<li>优先保留含问题关键词、标题路径和条款语义的块。</li>
<li>制度类按条款完整度加权。</li>
<li>最终给回答链路 3-5 条高质量证据。</li>
</ul>
</div>
<div class="card tone-amber">
<h3>回答层</h3>
<ul>
<li>能直接基于证据回答时,不强制二次模型整理。</li>
<li>模型只做压缩表达,不凭空补事实。</li>
<li>证据不足时明确说明缺什么。</li>
</ul>
</div>
</div>
</section>
<section id="delivery">
<div class="section-head">
<div>
<h2 class="section-title">实施路线</h2>
<p class="section-desc">
分四步小步交付。每一步都能单独验证,不把解析、索引、召回和评测揉成一次大改。
</p>
</div>
<span class="tag">渐进落地</span>
</div>
<div class="timeline">
<div class="phase">
<div class="phase-key">P0 / 文档落地</div>
<div class="phase-body">
<strong>先明确轻量边界</strong>
<span>完成本文档,确认不做重平台、不替换存储、不一次性引入复杂 OCR。</span>
</div>
</div>
<div class="phase">
<div class="phase-key">P1 / 统一解析</div>
<div class="phase-body">
<strong>补齐文件归集质量</strong>
<span>新增 Parser把 Word、PDF、Excel、CSV、TXT 稳定转为 Markdown并保存解析产物供索引复用。</span>
</div>
</div>
<div class="phase">
<div class="phase-key">P2 / 场景分块</div>
<div class="phase-body">
<strong>提升制度与表格命中率</strong>
<span>实现 laws、qa、table 三类分块。制度按章、节、条、款保留完整语义,表格保留 sheet、表头和行上下文。</span>
</div>
</div>
<div class="phase">
<div class="phase-key">P3 / 混合召回</div>
<div class="phase-body">
<strong>减少答偏和漏召回</strong>
<span>在 LightRAG 命中外补充关键词、条款标题、文件名召回,输出可控数量的证据块。</span>
</div>
</div>
<div class="phase">
<div class="phase-key">P4 / 轻量评测</div>
<div class="phase-body">
<strong>把效果优化变成可回归</strong>
<span>建设 30-50 条远光软件制度风格问答用例,覆盖报销、差旅、发票、预算、税务等高频问题。</span>
</div>
</div>
</div>
</section>
<section id="quality">
<div class="section-head">
<div>
<h2 class="section-title">验收标准</h2>
<p class="section-desc">
验收不只看页面状态,而要看文件是否真实入库、召回是否命中文档依据、
回答是否引用证据,以及并发访问时是否能稳定降级。
</p>
</div>
<span class="tag">真实验证</span>
</div>
<div class="checklist">
<div class="check">Word、PDF、Excel、CSV、TXT 文件能生成可读 Markdown且解析产物可复用。</div>
<div class="check">制度类文件能按章、节、条、款形成相对完整的证据块。</div>
<div class="check">Excel 表格问答能保留 sheet、表头、关键列和业务行上下文。</div>
<div class="check">Hermes 增量任务能区分解析失败、索引失败和归纳失败。</div>
<div class="check">常见制度问答优先返回证据化直接答案,模型超时时仍有可读降级答案。</div>
<div class="check">5-10 个用户同时访问时,查询候选数、重排数、模型调用数都有明确上限。</div>
<div class="check">轻量评测集覆盖至少 30 条问题,并记录命中文件、关键词和答案约束。</div>
<div class="check">不引入 Yuxi 平台级依赖,不改变现有知识库 UI 的主体交互。</div>
</div>
<p class="footnote">
后续实现时,优先在现有定向测试基础上补充 Parser、Chunking、Retrieval 和 Knowledge Eval 的小测试。
后端验证优先在 Docker 容器 <code>x-financial-main</code> 中运行。
</p>
</section>
<footer>
X-Financial 轻量知识库归集与问答优化开发文档 · 放置位置document/development/knowledge-answers/lightweight-knowledge-ingestion-design.html
</footer>
</main>
</div>
</body>
</html>

View File

@@ -0,0 +1,78 @@
# 本体字段治理
## 背景
当前费用申请、报销助手、单据详情、风险规则和预算控制中存在字段口径不一致的问题。例如同一语义在不同环节被命名为 `transport_type``transport_mode``application_transport_mode`,或 `occurred_date``business_time``time_range`。这些字段如果不先进入本体层,会导致语义识别、规则判断、草稿保存和前端展示各自解释同一业务事实。
## 原则
所有业务字段必须先设计为本体字段,再下放到业务模块使用。
- 本体字段注册表是唯一字段源。
- 业务层只允许消费本体 canonical 字段。
- 非本体字段只能作为输入别名,必须在语义入口归一。
- 页面控件字段、兼容字段、后端历史字段不能直接进入业务判断。
- 新增业务字段时,必须先更新本体字段设计,再更新表单、助手上下文、持久化、风险规则和测试。
## 当前第一阶段范围
第一阶段先治理费用申请和报销链路:
- 个人工作台意图识别。
- 费用申请预览和提交。
- 报销助手快速发起报销。
- 关联申请单生成报销草稿。
- 报销详情智能录入和附件归集。
- AI 预审、风险规则、审批流和预算流。
## 字段分层
本体 canonical 字段:
- `expense_type`
- `time_range`
- `location`
- `reason`
- `amount`
- `transport_mode`
- `attachments`
- `customer_name`
- `merchant_name`
- `participants`
- `application_claim_id`
- `application_claim_no`
- `application_days`
- `application_date`
- `application_lodging_daily_cap`
- `application_subsidy_daily_cap`
- `application_transport_policy`
- `application_policy_estimate`
输入兼容别名:
- `transport_type``transportMode``application_transport_mode` -> `transport_mode`
- `occurred_date``business_time``application_business_time` -> `time_range`
- `business_location``application_location` -> `location`
- `reason_value``business_reason``application_reason` -> `reason`
- `attachment_names` -> `attachments`
- `reimbursement_type``scene_label` -> `expense_type`
## 非合规判断
以下情况视为字段不合规:
- 新业务流程直接新增 `context_json` 字段但没有进入本体注册表。
- 风险规则读取未注册字段。
- 前端 `review_form_values` 输出页面控件字段。
- 后端服务用别名字段做业务判断,而不是先归一成本体字段。
- 同一业务事实在申请、报销、审批、预算中使用不同字段名。
## 验收口径
完成后应满足:
- 语义层能从上下文中生成统一本体实体。
- 报销助手关联申请单后不再因为字段别名丢失追问出行方式。
- `review_form_values` 对外输出本体字段,不输出页面别名字段。
- 后端测试覆盖别名归一到本体字段。
- 前端测试覆盖快速报销和核对抽屉只输出本体字段。

View File

@@ -0,0 +1,40 @@
# 本体字段纠察记录
## 纠察口径
所有会参与意图识别、申请/报销草稿、费用明细、风险规则、审批或预算判断的字段,必须先进入本体字段注册表。
字段分为三类:
- 本体业务字段:可被业务逻辑、规则、页面表单直接消费。
- 输入兼容别名:只允许在语义入口归一,不允许在业务判断中继续直接读取。
- 上下文元数据:只表达会话、上传、编辑态、权限和执行链路,不作为业务事实。
## 已注册的业务字段
- 费用事实:`expense_type``time_range``location``reason``amount``transport_mode``attachments`
- 对象事实:`customer_name``merchant_name``participants`
- 员工事实:`employee_name``employee_no``department_name``employee_position``employee_grade``manager_name`
- 预算事实:`budget_period``budget_subject``budget_amount``cost_center``warning_threshold``control_action`
- 申请关联事实:`application_claim_id``application_claim_no``application_days``application_date``application_policy_estimate`
## 已登记为元数据的字段
- 会话与流程:`conversation_id``conversation_history``conversation_scenario``conversation_intent``session_type``entry_source`
- 编辑与动作:`review_action``draft_claim_id``application_edit_mode``application_edit_claim_id`
- 上传与 OCR`attachment_count``attachment_names``ocr_documents``ocr_summary``review_document_form_values`
- 客户端运行态:`client_now_iso``client_timezone_offset_minutes`
- 权限与调试:`role_codes``is_admin``simulate_tool_failure``simulate_orchestrator_exception`
## 当前审计结论
- 未注册字段:已清零。
- 历史别名直接读取:主要集中在员工上下文顶层字段,例如 `name``grade``department``position`
- 第一轮已把申请/报销关键链路的表单字段统一到 `expense_type``time_range``location``reason``amount``transport_mode`
## 后续清理策略
1. 新增业务字段前,先更新 `ontology_field_registry.py`
2. 旧字段只作为输入别名保留,入口归一到 canonical 字段。
3. 业务模块逐步停止直接读取旧别名。
4. 使用 `server/scripts/audit_ontology_context_fields.py --strict` 作为收口质量闸。

View File

@@ -0,0 +1,15 @@
# 本体字段治理 TODO
- [x] 建立本体字段注册表,集中维护 canonical 字段和输入别名。[CONCEPT: 字段分层]
- [x] 在语义解析入口归一 `context_json.review_form_values`。[CONCEPT: 原则]
- [x] 在本体实体抽取中把上下文字段桥接为 `transport_mode``reason``location` 等实体。[CONCEPT: 当前第一阶段范围]
- [x] 报销助手 review 入口复用本体字段注册表,不再自己维护字段别名。[CONCEPT: 原则]
- [x] 快速报销关联申请单上下文去除 `business_time``business_location``reason_value``reimbursement_type` 等非本体输出字段。[CONCEPT: 非合规判断]
- [x] 核对抽屉提交上下文归一为本体字段。[CONCEPT: 验收口径]
- [x] 补充本体层和前端字段归一回归测试。[CONCEPT: 验收口径]
- [ ] 清查申请助手字段:`application_preview``application_fields``business_time_context` 是否都已归一本体。
- [ ] 清查报销详情字段:智能录入、附件归集、费用明细、异常说明是否仍有非本体字段直传。
- [ ] 清查风险规则字段规则中心、Hermes 归一字段、OCR pipeline 字段是否有未注册业务字段。
- [ ] 清查预算字段:预算控制、预算复核、预算操作上下文是否全部使用本体字段。
- [ ] 清查审批字段:审批意见、退回原因、流程节点字段是否需要纳入本体或定义为流程元数据。
- [ ] 增加字段合规扫描脚本,对新增 `review_form_values` / `context_json` 字段进行检查。

View File

@@ -0,0 +1,266 @@
# 票据夹功能概念文档
更新时间2026-05-29
## 功能一句话
票据夹用于归集用户已上传并经过 OCR 识别的原始票据文件,避免票据已识别但忘记关联报销单后无法找回。
## 背景与问题
当前系统有两条票据路径:
- 报销明细附件路径:票据上传到某个草稿费用明细后,会存入 `expense_claims` 附件目录,并写入附件元数据。
- 独立 OCR 识别路径:报销对话里先上传票据识别时,`/ocr/recognize` 只返回识别结果,源文件使用临时目录,识别结束后会清理。
这会导致一个业务缺口:用户可能已经上传票据并完成 OCR但还没有把票据关联到报销草稿。只要用户关闭会话、切走页面或忘记继续操作原始票据就没有一个稳定入口可追溯。
票据夹要补齐这个缺口:凡是系统对用户上传文件做过 OCR 并持久化源文件,就应进入票据夹列表;后续用户可以查看、修正票据信息、删除无效票据,或一键把未关联票据带入报销对话。
## 目标与非目标
目标:
- 在左侧侧边栏的“单据中心”下面新增“票据夹”入口。
- 建立票据源文件持久化能力OCR 后保留原始文件、预览文件和识别元数据。
- 提供票据夹列表,复用单据中心的紧凑列表视觉语言。
- 支持“未关联票据 / 已关联票据”两个状态切换。
- 支持票据详情:基本票据信息可编辑、原始文件可预览、底部返回列表和删除票据。
- 支持“一键关联票据”:选择未关联票据,选择未提交草稿或新建报销单,再跳转到报销对话继续填写和关联。
非目标:
- 本轮不引入 `document_assets` 等数据库结构变更;先用文件资产和元数据 JSON 完成产品闭环。
- 本轮不替换现有报销明细附件接口。
- 本轮不把票据夹做成财务共享的全公司档案库;默认只展示当前登录用户自己的票据。
- 本轮不在列表页直接完成报销单提交,提交仍回到现有对话核对流程。
## 用户与场景
涉及角色:
- 普通员工:上传票据后稍后再归集到草稿。
- 经理或财务用户:在自己名下上传票据时同样需要留存和追溯。
典型场景:
1. 用户在个人工作台上传 3 张票据OCR 成功后暂时没有保存草稿。
2. 用户第二天打开票据夹,看到这 3 张票据仍在“未关联票据”。
3. 用户进入详情,修正票据类型、金额或日期。
4. 用户点击“一键关联票据”,多选未关联票据。
5. 用户选择已有草稿,或选择新建报销单。
6. 系统打开报销对话,把票据源文件和 OCR 信息带入现有核对流程。
## 功能能力
### 票据持久化
- OCR 入口接收文件后,在识别完成阶段保存源文件。
- 保存位置建议为 `storage/receipt_folder/<owner_key>/<receipt_id>/`
- 每个票据目录包含:
- 原始文件:`source.<ext>`
- 预览文件:`preview.<ext>`,可为空
- 元数据:`meta.json`
- 元数据记录:
- `id`
- `owner_key`
- `file_name`
- `media_type`
- `size_bytes`
- `uploaded_at`
- `status`: `unlinked` / `linked`
- `linked_claim_id`
- `linked_claim_no`
- `linked_item_id`
- `linked_at`
- OCR 引擎、模型、文本、摘要、置信度、票据类型、场景、结构化字段、提示信息
### 列表
- 页签:
- 未关联票据
- 已关联票据
- 表格字段建议:
- 票据文件
- 识别类型
- 费用场景
- 金额
- 票据日期
- OCR 置信度
- 关联状态
- 上传时间
- 交互:
- 搜索文件名、摘要、字段值、关联单号
- 按状态切换
- 点击行进入详情
- 未关联页显示“一键关联票据”
### 详情
- 基本票据信息:
- 文件名只读
- 票据类型可编辑
- 费用场景可编辑
- 票据日期可编辑
- 金额可编辑
- 商户 / 出发地 / 到达地 / 票据号码等 OCR 字段可编辑
- 原始文件展示:
- 图片直接预览
- PDF 用浏览器内嵌预览
- 不可预览类型提供下载入口
- 底部动作:
- 返回列表
- 删除票据
### 一键关联票据
流程:
1. 打开关联弹窗,展示未关联票据多选列表。
2. 下一步展示当前用户未提交草稿报销单,也提供“新建报销单”选项。
3. 确认后打开现有报销对话。
4. 如果选择已有草稿:
- 对话以 `link_to_existing_draft` 语义继续。
- 携带 `draft_claim_id` 和票据文件。
5. 如果选择新建报销单:
- 对话以 `create_new_claim_from_documents` 语义继续。
- 携带票据文件和 OCR 元数据。
## 方案设计
### 后端
新增模块:
- `schemas/receipt_folder.py`
- `services/receipt_folder.py`
- `api/v1/endpoints/receipt_folder.py`
接口建议:
- `GET /api/v1/receipt-folder?status=unlinked|linked|all`
- `GET /api/v1/receipt-folder/{receipt_id}`
- `PATCH /api/v1/receipt-folder/{receipt_id}`
- `DELETE /api/v1/receipt-folder/{receipt_id}`
- `GET /api/v1/receipt-folder/{receipt_id}/preview`
- `GET /api/v1/receipt-folder/{receipt_id}/source`
OCR 改造:
- `/api/v1/ocr/recognize` 保持现有响应结构兼容。
- 在识别后调用票据夹服务保存源文件和识别结果。
- 给每个返回的 OCR 文档补充可选 `receipt_id``receipt_preview_url``receipt_source_url` 字段。
### 前端
新增模块:
- `services/receiptFolder.js`
- `views/ReceiptFolderView.vue`
- `assets/styles/views/receipt-folder-view.css`
导航改造:
- `useNavigation.js` 新增 `receiptFolder`,放在 `documents` 后面。
- `accessControl.js``receiptFolder` 作为默认可见视图。
- `router/index.js` 自动生成 `/app/receiptFolder` 路由。
- `AppShellRouteView.vue` 渲染新页面,并允许页面触发 `openSmartEntry`
对话衔接:
- 票据夹确认关联时,前端从 `source` 接口取回 Blob构造 `File` 对象传给 `openSmartEntry`
- 同时把已编辑 OCR 元数据转为 `initialReceiptDocuments` 或直接通过 `prompt` / `extraContext` 进入对话。
- 本轮优先用现有 `initial-files``initial-prompt` 打开对话,确保用户可以继续核对和保存。
## 算法与公式
当前功能不涉及显式数学公式。
列表排序使用上传时间倒序:
$$
sortKey(receipt) = uploadedAt(receipt)
$$
状态归类:
$$
status(receipt) =
\begin{cases}
linked, & linkedClaimId \neq \emptyset \\
unlinked, & linkedClaimId = \emptyset
\end{cases}
$$
## 测试方案
后端:
- OCR 识别后会保存源文件和 `meta.json`
- 列表只返回当前用户票据。
- `status=unlinked` 只返回未关联票据。
- 详情可读取 OCR 字段。
- PATCH 后字段持久化。
- 预览接口能返回图片或 PDF。
- DELETE 只删除票据夹根目录下的目标票据。
前端:
- 导航中“票据夹”位于“单据中心”下面。
- 列表空态、加载态、错误态可用。
- 未关联和已关联两个页签计数正确。
- 点击行进入详情。
- 详情可保存字段、返回列表、删除票据。
- 一键关联弹窗能完成票据选择和草稿选择。
集成:
- 上传票据触发 OCR 后,票据出现在票据夹。
- 从票据夹选择未关联票据,可打开报销对话。
- 选择已有草稿时,对话带入草稿单号。
- 选择新建报销单时,对话提示基于票据新建。
## 指标与验收
- OCR 成功返回后,票据夹列表能查到对应源文件。
- 票据源文件和预览文件在重启后仍可访问。
- 未关联票据和已关联票据状态切换正确。
- 票据详情字段修改后刷新仍保留。
- 删除票据后列表不再显示,预览接口返回 404。
- 侧边栏位置符合要求:票据夹在单据中心下面。
- 单个新增核心前端和后端模块不超过 800 行。
## 风险与开放问题
- 当前报销草稿流主要持久化 OCR 文本和文件名,真实文件复制到报销明细附件目录仍需要进一步打通。
- 本轮采用文件元数据而非数据库,适合先完成闭环;后续若需要审计、权限、跨用户协作和全文检索,应升级到资产表。
- 已关联状态如何自动回写,需要在后续把票据夹 ID 与报销明细 `invoice_id` 建立更强绑定。
- 多票据关联时,如果用户中途取消对话,本轮仍保留为未关联,避免误标。
## 2026-06-03 详情页与上传治理补充
本轮根据新的验收要求收敛为三块核心内容:
- 左侧为票据预览,使用共享详情页主区域承载,图片和 PDF 都以完整票据可见为优先目标,不再提供“打开源文件”按钮。
- 右侧为识别票据详情,展示当前票据所有 OCR 字段和基础字段;用户点击“编辑”后可直接修改识别内容,保存后写回票据夹元数据。
- 底部为关联信息;左侧预览卡底部同时展示用户编辑操作记录,用于后续财务判断人工修改痕迹。
编辑记录治理:
- `PATCH /receipt-folder/{receipt_id}` 在保存前后对可编辑票据信息做字段级 diff。
- 每条编辑日志记录操作者、操作时间、字段名称、修改前值、修改后值。
- 前端详情页只展示真实 `edit_logs`,不再用模拟操作日志替代。
重复上传治理:
- OCR 持久化票据时计算源文件 `sha256`
- 同一用户再次上传相同源文件时,不新建票据目录,返回已有 `receipt_id`,并在 OCR 文档 warnings 中提示“已上传过同样的单据,请不要重复上传。”
报销助手联动:
- 用户在报销助手上传新附件前,如果票据夹中存在未关联票据,先提示用户是否进入票据夹关联。
- 用户可以选择“去票据夹关联”,也可以选择“继续上传新附件”;继续上传时只跳过本次未关联提醒,不影响后续重复附件校验。
删除级联:
- 已关联票据对应的报销单被删除时,票据夹中关联该报销单的票据源文件、预览文件和元数据一并删除。

View File

@@ -0,0 +1,114 @@
# 票据夹功能 TODO
更新时间2026-05-29
## 阶段一:调研与契约
- [x] 梳理现有单据中心导航、列表样式和详情入口。[CONCEPT: 方案设计]
证据:已确认 `DocumentsCenterView.vue``useNavigation.js``AppShellRouteView.vue` 是前端入口。
- [x] 梳理现有 OCR 和报销附件存储链路。[CONCEPT: 背景与问题]
证据:已确认 `/ocr/recognize` 只临时识别;报销明细附件由 `expense_claim_attachment_*` 写入 `expense_claims` 存储。
- [x] 确定本轮不做数据库结构变更,先用票据文件资产和元数据 JSON 完成闭环。[CONCEPT: 目标与非目标]
证据:避免新增迁移,降低本轮开发风险。
## 阶段二:文档
- [x] 创建 `document/development/receipt-folder/CONCEPT.md`。[CONCEPT: 全文]
证据:本文档已落地。
- [x] 创建 `document/development/receipt-folder/TODO.md`。[CONCEPT: 测试方案]
证据:本文档已落地。
## 阶段三:后端票据资产层
- [x] 新增 `schemas/receipt_folder.py`,定义列表项、详情、字段更新和删除响应。[CONCEPT: 后端]
证据:已新增 `ReceiptFolderItemRead``ReceiptFolderDetailRead``ReceiptFolderUpdate``ReceiptFolderDeleteResponse`
- [x] 新增 `services/receipt_folder.py`,负责源文件保存、元数据读写、预览解析、列表过滤和安全路径校验。[CONCEPT: 票据持久化]
证据:`ReceiptFolderService` 已覆盖 OCR 批量持久化、已关联附件同步、详情更新、预览/源文件解析与目录安全校验。
- [x] 新增 `api/v1/endpoints/receipt_folder.py`,暴露列表、详情、更新、删除、预览和源文件接口。[CONCEPT: 后端]
证据:已提供 `GET/PATCH/DELETE /receipt-folder/{receipt_id}``preview/source` 文件接口。
- [x]`api/v1/router.py` 注册票据夹接口。[CONCEPT: 后端]
证据:已 include `receipt_folder_router`
- [x] 改造 `/ocr/recognize`OCR 后保存源文件并把 `receipt_id` 等可选字段带回前端。[CONCEPT: OCR 改造]
证据:`OcrRecognizeDocumentRead` 已补充 `receipt_id``receipt_status``receipt_preview_url``receipt_source_url`;来源于票据夹的 `receipt_ids` 会复用原票据,避免重复入库。
## 阶段四:前端票据夹页面
- [x] 新增 `services/receiptFolder.js`,封装票据夹接口和 Blob 文件读取。[CONCEPT: 前端]
证据:已封装列表、详情、更新、删除、文件读取和 `buildReceiptFile`
- [x] 新增 `ReceiptFolderView.vue`,实现列表、状态页签、搜索、一键关联入口和详情切换。[CONCEPT: 列表]
证据:页面已包含未关联/已关联页签、搜索、表格、详情、编辑、预览和删除动作。
- [x] 新增 `receipt-folder-view.css`,复用单据中心紧凑企业级视觉,避免继续拉大现有 `DocumentsCenterView.vue`。[CONCEPT: 列表]
证据:票据夹样式独立落在 `assets/styles/views/receipt-folder-view.css`,核心文件均未超过 800 行。
- [x]`useNavigation.js` 增加 `receiptFolder`,并放在 `documents` 后面。[CONCEPT: 前端]
证据:`appViews``navItems``receiptFolder` 均紧跟 `documents`
- [x]`accessControl.js` 增加默认可见权限和默认路由顺序。[CONCEPT: 前端]
证据:已加入 `DEFAULT_APP_VIEW_ORDER``ALWAYS_VISIBLE_VIEWS`
- [x]`AppShellRouteView.vue` 渲染票据夹页面,并让页面可打开报销对话。[CONCEPT: 一键关联票据]
证据:已接入 `ReceiptFolderView` 并转发 `open-assistant``openSmartEntry`
## 阶段五:一键关联流程
- [x] 实现未关联票据多选弹窗第一步。[CONCEPT: 一键关联票据]
证据:`ElDialog` 第一阶段使用 `ElCheckboxGroup` 多选未关联票据。
- [x] 实现未提交草稿选择和“新建报销单”选择第二步。[CONCEPT: 一键关联票据]
证据:第二阶段读取草稿报销单,并保留 `新建报销单` 选项。
- [x] 从票据源文件接口取回 Blob 并构造 `File` 对象传给报销对话。[CONCEPT: 对话衔接]
证据:`buildReceiptFile``source_url` 读取 Blob 并生成带 `receiptId``File`
- [x] 选择已有草稿时,打开对话并带入草稿单号和关联提示。[CONCEPT: 一键关联票据]
证据:选择草稿后以 `source: 'detail'``request` 和关联 prompt 打开报销对话;附件上传会携带 `receipt_id` 并回写原票据为已关联。
- [x] 选择新建报销单时,打开对话并带入基于票据新建的提示。[CONCEPT: 一键关联票据]
证据:新建路径以 `source: 'receipt-folder'` 携带票据文件和新建 prompt。
## 阶段六:测试与验证
- [x] 补充后端票据夹服务和接口测试,超时时间控制在 60s 内。[CONCEPT: 测试方案]
证据:`docker exec x-financial-main ... pytest server/tests/test_ocr_endpoints.py server/tests/test_reimbursement_endpoints.py -q` 通过8 passed耗时 11.41s。
- [x] 补充前端导航和票据夹视图模型测试。[CONCEPT: 测试方案]
证据:`navigation-route-resolution.test.mjs` 已覆盖路由顺序,新增 `receipt-folder-view.test.mjs` 覆盖视图关键能力。
- [x] 运行前端构建或定向测试。[CONCEPT: 指标与验收]
证据:`node web/tests/navigation-route-resolution.test.mjs``node web/tests/receipt-folder-view.test.mjs``npm.cmd run build` 均通过。
- [x] 在 Docker `x-financial-main``/app` 内运行后端定向测试。[CONCEPT: 测试方案]
证据:`pytest server/tests/test_ocr_endpoints.py server/tests/test_reimbursement_endpoints.py -q` 在容器内通过8 passed。
- [x] 手动核对侧边栏位置、列表密度、详情预览和关联弹窗。[CONCEPT: 指标与验收]
证据:内置浏览器打开 `http://localhost:5173/app/receiptFolder`,侧边栏中“票据夹”位于“单据中心”下方,未关联/已关联页签与空态渲染正常,控制台无相关错误。
## 阶段七:收口
- [x] 回看 `CONCEPT.md` 验收标准,确认已实现项均有证据。[CONCEPT: 指标与验收]
证据OCR 持久化、列表/详情/预览、侧边栏位置、一键关联入口和文件行数约束均已覆盖。
- [x] 更新本 TODO 的完成状态和验证记录。[CONCEPT: 测试方案]
证据:本文件已补充完成勾选和验证命令记录。
## 阶段八2026-06-03 详情页与上传治理收口
- [x] 将票据夹详情页收敛为共享详情布局下的三块内容:左侧完整预览、右侧识别票据详情、底部关联信息。[CONCEPT: 2026-06-03 详情页与上传治理补充]
证据:`node web/tests/receipt-folder-view.test.mjs``npm.cmd run build`、容器内 `cd /app/web && npm run build` 均通过。
- [x] 支持识别票据详情编辑,并在后端保存字段级编辑日志。[CONCEPT: 编辑记录治理]
证据:容器内 `pytest -q server/tests/test_ocr_endpoints.py server/tests/test_receipt_folder_service.py` 通过3 passed。
- [x] OCR 持久化时识别同一用户重复上传的相同源文件,返回已有票据并提示不要重复上传。[CONCEPT: 重复上传治理]
证据:`test_ocr_endpoints.py` 已覆盖重复上传返回原 `receipt_id` 和 warnings。
- [x] 报销助手上传附件前提示票据夹中存在未关联票据,并提供进入票据夹关联或继续上传的建议动作。[CONCEPT: 报销助手联动]
证据:`receipt-folder-view.test.mjs` 覆盖 `fetchReceiptFolderItems('unlinked')``open_receipt_folder``continue_upload_with_unlinked_receipts`
- [x] 删除已关联报销单时,同步删除票据夹中关联该报销单的票据文件。[CONCEPT: 删除级联]
证据:`test_receipt_folder_service.py` 已覆盖 `delete_receipts_for_claim` 删除后不可再读取票据。

View File

@@ -0,0 +1,137 @@
# 报销草稿分支动作收口 概念文档
更新时间2026-06-23
## 功能一句话
当用户发起报销且系统命中可继续的报销草稿时,只提供“查看草稿、继续关联草稿、独立新建报销单”三个明确入口,让用户能看详情、补附件/说明,或确认另起一张新草稿。
## 背景与问题
- 当前现状AI 工作台和报销助手在“我要报销”后会先查询可继续报销草稿;命中草稿时,当前按钮把“继续草稿”和“打开详情”混在一起,并把跳过草稿描述成“关联申请单新建报销单”。
- 用户痛点:按钮语义不清,用户无法判断点击“继续草稿”是打开详情、继续补附件,还是进入申请单关联。
- 业务影响:报销草稿与新建报销单的路径混杂,容易造成重复草稿、附件归集错误或用户误以为已继续处理。
- 为什么现在需要做:截图中的草稿分支是报销入口的第一屏决策,需要先把按钮数量、文案和后续状态固定下来,再继续开发。
## 目标与非目标
### 目标
- [G1] 命中可继续报销草稿时,快捷按钮固定为三个:查看草稿、继续关联草稿、独立新建报销单。
- [G2] “查看草稿”只负责跳转详情页,不承担继续上传或新建逻辑。
- [G3] “继续关联草稿”只负责把当前会话切到“等待上传附件或补充说明”的状态,并锁定目标草稿。
- [G4] “独立新建报销单”先提示用户确认是否新建草稿单据,再进入新草稿创建流程。
### 非目标
- [NG1] 本轮不改后端草稿保存、附件 OCR、风险审核和审批流规则。
- [NG2] 本轮不改变申请单关联命中时的“选择申请单 / 单独新建报销单”逻辑。
- [NG3] 本轮不重做报销助手整体 UI只收口草稿命中态的按钮和动作流。
## 用户与场景
- 目标用户:普通员工在个人工作台 AI 模式或报销助手中发起报销。
- 使用入口:快捷操作“发起报销”、输入“我要报销 / 发起报销 / 新建报销”。
- 核心场景:
1. 系统查到可继续报销草稿,展示草稿卡片和三个按钮。
2. 用户点击“查看草稿”,打开对应单据详情页。
3. 用户点击“继续关联草稿”,系统提示上传相关附件或补充说明。
4. 用户点击“独立新建报销单”,系统询问是否新建草稿单据。
- 异常场景:
- 草稿缺少 `claim_id` 时,“查看草稿”和“继续关联草稿”不能提交无目标动作。
- 历史会话里的旧动作仍可兼容处理,不影响新生成提示。
## 功能能力
- [C1] 输入能力:读取报销草稿候选单据,识别 `claim_id``claim_no`、状态、金额、时间和事由。
- [C2] 处理能力:将草稿命中态动作拆成查看、继续关联、独立新建三条互斥分支。
- [C3] 输出能力:输出固定三按钮,并在点击后生成明确的用户回显和助手提示。
- [C4] 状态与权限:继续关联时记录目标草稿,后续上传附件或补充说明应围绕该草稿继续。
- [C5] 边界与降级:保留旧 `skip_reimbursement_draft_check` 动作兼容,避免历史会话按钮失效。
## 方案设计
### 前端
- 页面/组件:
- `travelReimbursementAssociationGateModel.js` 负责生成草稿命中态文案和三个动作。
- `useWorkbenchAiActionRouter.js` 负责个人工作台 AI 模式的动作分流。
- `useWorkbenchAiExpenseFlow.js` 负责个人工作台中的继续关联提示和独立新建确认提示。
- `useTravelReimbursementSuggestedActions.js` 负责报销助手页面中的相同动作分流。
- 交互状态:
- 查看草稿:沿用 `open_application_detail`,只跳转详情。
- 继续关联草稿:新增动作类型,点击后提示“请上传相关附件,或补充说明”,并记录目标草稿。
- 独立新建报销单:新增动作类型,点击后提示“是否新建草稿单据”,确认后进入现有单独新建流程。
- 展示规则:
- 草稿命中态只显示三个按钮,不再出现“继续草稿”或“不用草稿,关联申请单新建报销单”。
- 按钮文案携带草稿编号,方便用户辨认目标。
- 降级处理:
- 历史旧动作仍走原有分支。
- 缺少草稿 ID 时给出 toast不继续进入无目标关联。
### 后端
- 接口/服务:当前不新增接口。
- 权限与校验:沿用现有详情页与草稿操作权限。
- 持久化:当前不改后端持久化结构。
- 降级处理:后续上传附件或保存草稿仍使用现有 orchestrator 与附件归集能力。
### 算法与规则
- 输入:已筛选出的报销草稿候选。
- 流程:按更新时间排序后取首个草稿作为三按钮默认目标;草稿卡片仍展示候选详情。
- 输出:三个动作对象及后续提示文案。
- 解释:本轮不是匹配算法改造,只是草稿命中后的动作语义收口。
### 数据与契约
- 核心字段:`claim_id``claim_no``original_message``draft_claim_id``selected_claim_no`
- 状态枚举:新增前端动作类型 `continue_reimbursement_draft_association``create_standalone_reimbursement_draft``cancel_standalone_reimbursement_draft`
- 兼容策略:保留 `open_application_detail` 和旧跳过动作分支。
- 版本/审计:通过前端测试锁定动作数量、文案和路由行为。
## 算法与公式
当前功能不涉及显式数学公式。
## 测试方案
后端:
- 当前不新增后端测试;本轮没有修改后端服务或接口。
前端:
- 扩展 `workbench-ai-reimbursement-association-gate.test.mjs`,验证草稿命中态只输出三个动作和新文案。
- 扩展 `workbench-ai-action-router.test.mjs`,验证继续关联、独立新建确认的路由行为。
- 扩展 `travel-reimbursement-guided-flow.test.mjs` 或既有报销助手动作测试,验证旧报销助手使用相同动作语义。
集成:
- 运行相关 Node 测试,确认 AI 工作台和报销助手入口没有回退到旧按钮。
手工验证:
- 在个人工作台 AI 模式输入“我要报销”,命中草稿后检查按钮数量和点击行为。
## 指标与验收
- [A1] 功能验收:草稿命中态固定显示三个按钮,且第一个按钮跳详情,第二个按钮提示上传附件/说明,第三个按钮提示是否新建草稿单据。
- [A2] 性能指标:不增加额外接口查询;仍复用一次单据列表查询。
- [A3] 质量指标:定向前端测试通过,旧动作兼容测试不失效。
- [A4] 安全/权限指标:不绕过详情页和草稿操作原有权限。
- [A5] 可观测性:对话消息中能看到用户选择了哪个分支。
## 风险与开放问题
- 风险:多个草稿同时命中时,三个按钮默认指向最新草稿;用户如需其他草稿,可先通过卡片查看信息后进入详情页处理。
- 风险:全量 `code-size-limits` 当前仍会被既有 `TopBar.vue:824` 阻断;本轮新增和修改的文件均已控制在 800 行内。
- 已处理依赖:复用现有详情页跳转、报销场景选择和草稿保存链路。
- 待确认:后续是否要在草稿卡片内为每张草稿提供独立按钮;本轮先按截图中的三按钮入口收口。
- 降级策略:旧历史会话按钮保持可点击,不强制迁移旧消息。
## 本轮实现记录
- 2026-06-23先落本文档和 TODO再按测试驱动修改前端草稿分支动作。
- 2026-06-23新增 `travelReimbursementDraftBranchModel.js` 承载草稿三分支动作,避免继续放大 `travelReimbursementAssociationGateModel.js`
- 2026-06-23个人工作台和报销助手页面均已接入“继续关联草稿”和“独立新建报销单”的后续提示。

View File

@@ -0,0 +1,73 @@
# 报销草稿分支动作收口 开发 TODO
更新时间2026-06-23
## 使用规则
- 每个 TODO 必须对应 `CONCEPT.md` 中的目标、能力、方案或验收点。
- 只有完成并验证后,才能把 `[ ]` 改成 `[x]`
- 勾选时在任务后补充简短证据,例如文件、接口、命令或验证结果。
- 如果需求发生变化,先更新 `CONCEPT.md`,再调整本 TODO。
## 1. 调研与边界
- [x] [CONCEPT: 背景与问题] 阅读相关页面、动作模型和测试,确认当前“继续草稿”实际走详情打开,“不用草稿”走申请单关联。
证据:`travelReimbursementAssociationGateModel.js``useWorkbenchAiActionRouter.js``useWorkbenchAiExpenseFlow.js``workbench-ai-reimbursement-association-gate.test.mjs`
- [x] [CONCEPT: 目标与非目标] 确认本轮只改草稿命中态按钮与点击流,不改后端草稿保存和风险审核。
证据:`CONCEPT.md` 的目标与非目标章节。
- [x] [CONCEPT: 风险与开放问题] 标记多草稿命中时默认指向最新草稿,历史旧动作保留兼容。
证据:`CONCEPT.md` 的风险与开放问题章节。
## 2. 契约与设计
- [x] [CONCEPT: 功能能力] 定义三个动作分支:查看草稿、继续关联草稿、独立新建报销单。
证据:`CONCEPT.md` 的功能能力和方案设计章节。
- [x] [CONCEPT: 方案设计] 明确个人工作台 AI 模式与报销助手页面共用动作模型,但分别在各自 action router 中处理点击。
证据:`CONCEPT.md` 的前端方案设计章节。
- [x] [CONCEPT: 算法与公式] 明确本轮不涉及显式数学公式。
证据:`CONCEPT.md` 的算法与公式章节。
- [x] [CONCEPT: 指标与验收] 把验收标准拆成按钮数量、按钮文案、点击后提示和旧动作兼容。
证据:`CONCEPT.md` 的指标与验收章节。
## 3. 后端实现
- [x] [CONCEPT: 后端] 本轮不新增后端 schema、service、endpoint、权限和持久化逻辑。
证据:`CONCEPT.md` 明确当前不新增接口。
- [x] [CONCEPT: 数据与契约] 后端响应结构不变,新增内容仅为前端动作类型。
证据:`CONCEPT.md` 的数据与契约章节。
## 4. 算法/规则实现
- [x] [CONCEPT: 算法与规则] 本轮不改候选单据筛选算法,只改命中后的动作分支。
证据:`CONCEPT.md` 的算法与规则章节。
- [x] [CONCEPT: 功能能力] 明确旧动作保留兼容,不删除历史会话能力。
证据:`CONCEPT.md` 的边界与降级说明。
## 5. 前端实现
- [x] [CONCEPT: 前端] 在草稿分支模型中新增动作类型和三按钮生成逻辑。
证据:`travelReimbursementDraftBranchModel.js` 定义 `CONTINUE_REIMBURSEMENT_DRAFT_ACTION``CREATE_STANDALONE_REIMBURSEMENT_DRAFT_ACTION` 和三按钮构造;`travelReimbursementAssociationGateModel.js` re-export 保持兼容。
- [x] [CONCEPT: 前端] 在个人工作台 AI 模式中处理继续关联草稿、独立新建确认和取消新建。
证据:`useWorkbenchAiActionRouter.js` 分流新动作;`useWorkbenchAiExpenseFlow.js` 追加上传附件/说明提示和新建草稿确认提示。
- [x] [CONCEPT: 前端] 在报销助手页面中处理同一批新动作,保持与工作台一致。
证据:`useTravelReimbursementSuggestedActions.js` 接入继续关联、独立新建确认和取消新建;`TravelReimbursementCreateView.js` 传入 `draftClaimId``composerUploadIntent`
- [x] [CONCEPT: 前端] 保留旧动作兼容,不破坏历史会话按钮。
证据:`SKIP_REIMBURSEMENT_DRAFT_CHECK_ACTION``SKIP_REQUIRED_APPLICATION_LINK_ACTION` 仍由原路径处理;相关旧链路测试通过。
## 6. 测试与验证
- [x] [CONCEPT: 测试方案] 先补充失败的前端单元测试,覆盖三按钮生成和路由行为。
证据RED 阶段 `workbench-ai-reimbursement-association-gate.test.mjs``workbench-ai-action-router.test.mjs` 因缺少 `CONTINUE_REIMBURSEMENT_DRAFT_ACTION` 导出失败。
- [x] [CONCEPT: 测试方案] 实现后运行定向前端测试,记录通过结果。
证据:`node --test web/tests/workbench-ai-reimbursement-association-gate.test.mjs``node --test web/tests/workbench-ai-action-router.test.mjs``node --test web/tests/travel-reimbursement-guided-flow.test.mjs``node --test web/tests/travel-reimbursement-review-drawer-switch.test.mjs``node --test web/tests/expense-attachment-draft-selection.test.mjs``node --test web/tests/attachment-association-confirmation.test.mjs` 均通过。
- [x] [CONCEPT: 指标与验收] 回看验收点,确认没有旧文案继续出现在新草稿命中态。
证据:`workbench-ai-reimbursement-association-gate.test.mjs` 断言新草稿命中态有且仅有三个动作,并不再出现“跳过草稿后再关联申请单”。
## 7. 文档收尾
- [x] [CONCEPT: 指标与验收] 实现完成后更新本 TODO 的证据。
证据:本 TODO 已回填实现文件和测试命令。
- [x] [CONCEPT: 风险与开放问题] 根据实现结果更新剩余风险。
证据:`CONCEPT.md` 已记录全量 `code-size-limits` 仍被既有 `TopBar.vue:824` 阻断;本轮文件行数为 `travelReimbursementAssociationGateModel.js:714``travelReimbursementDraftBranchModel.js:143`
- [x] [CONCEPT: 功能一句话] 确认最终实现没有偏离原始目标。
证据:新草稿命中态固定为查看草稿、继续关联草稿、独立新建报销单三个入口。

View File

@@ -0,0 +1,581 @@
# 风险规则可解释流程判断改造方案
## 功能一句话
把风险规则从“自然语言生成一段 JSON”升级为“自然语言、字段本体、可执行 JSON DSL、流程判断图、测试命中路径、版本修改”一致闭环让业务用户能看懂规则怎么判断让系统按同一套逻辑执行。
## 背景与问题
当前风险规则已经具备自然语言创建、JSON 风险规则、风险评分、详情页流程图、仿真测试和上线启用能力,但仍有几个关键缺口:
- 规则解释不够稳定。用户输入复杂业务规则后,系统可能把“城市是否一致、日期是否越界、是否存在合理说明”解释成“是否出现关键词”,这会导致业务语义失真。
- 流程图容易变成展示装饰。如果流程图不严格从可执行 JSON DSL 派生,就会出现“页面看起来是 A后端实际执行是 B”的问题。
- 测试结果缺少路径解释。用户上传票据和输入意图后,需要知道系统识别到了哪些字段、走过哪些判断节点、为什么命中或未命中。
- 规则修改缺少版本化闭环。已上线规则不能直接覆盖,应创建修订版本,旧版本继续生效,新版本测试通过后再替换。
- 常见费控规则需要模板化扩展。预算、票据、差旅、招待、采购/AP、企业卡等规则应进入规则模板库但仍必须走同一套解释和执行链路。
## 目标与非目标
### 目标
- [G1] 自然语言规则经过 Hermes 语义理解后,生成结构稳定、可校验、可执行的 JSON DSL。
- [G2] 流程判断图必须由 JSON DSL 派生,不能直接由自然语言单独生成。
- [G3] 详情页展示“文字流程解释 + 流程图 + 使用字段 + 风险分数 + 规则状态”,让业务用户能确认系统理解是否正确。
- [G4] 测试规则时展示本次样例或票据仿真的字段识别结果、判断路径、命中节点和最终结论。
- [G5] 用户觉得规则不合理时,通过“创建修订版本”修改,线上版本保持稳定。
- [G6] 常见费控规则模板库可以复用同一套 DSL、流程图和测试机制。
### 非目标
- [NG1] 本期不做流程图编辑器,不允许拖拽、改节点、缩放编辑或在线画图。
- [NG2] 本期不让大模型作为风险命中裁判。Hermes 只负责理解、生成、解释和辅助解析,最终命中由规则执行器决定。
- [NG3] 本期不把所有复杂政策一次性建成完整专家系统,先保证规则表达、解释和执行一致。
- [NG4] 本期不直接覆盖已上线规则,所有线上修改都走修订版本。
## 用户与场景
- 财务规则制定者:创建风险规则,查看系统理解是否正确,修改草稿规则。
- 高级财务人员 / admin审核、上线、下线、启用、停用、删除未发布规则。
- 普通报销用户:在真实业务命中风险时看到简明原因,可反馈误判或漏判。
- 系统执行链路:报销、费用申请、预算占用、票据识别、采购/AP 等场景只加载已上线且已启用的规则。
核心场景:
1. 新建规则:输入规则标题、费用业务环节、费用领域、是否需要附件、自然语言规则。
2. 生成规则Hermes 结合字段本体输出 JSON DSL、业务说明、风险评分、流程模型和 SVG。
3. 查看详情:用户确认“系统理解的字段、判断条件、例外说明、命中动作”是否正确。
4. 仿真测试:用户上传附件并输入测试意图,系统统一识别字段,再由执行器判断当前规则。
5. 修改规则:未上线规则直接编辑;已上线规则创建修订版本,测试通过后发布替换。
## 功能能力
### C1. 自然语言输入能力
新建风险规则表单应包含:
- 规则标题。
- 业务环节:费用申请、报销、预算控制、付款/采购等。
- 费用领域:差旅、住宿、交通、招待、办公、培训、会议、软件服务、通讯、福利、预算、发票、采购/AP、通用。
- 是否需要附件:需要时测试弹窗开放附件上传;不需要时隐藏上传入口。
- 自然语言规则描述。
风险等级不允许用户手动选择,由评分模型输出风险分数和等级。
### C2. 语义理解与字段本体映射
Hermes 需要输出一份中间语义计划,而不是直接写死 JSON
- 规则意图:判断什么业务风险。
- 适用范围:业务环节、费用领域、费用科目、单据类型。
- 所需字段:中文解释、英文字段名、来源、是否必填。
- 票据字段OCR 或文档智能识别得到的城市、日期、金额、销售方、发票号等。
- 判断步骤:按顺序表达条件、分支、例外说明和命中动作。
- 例外条件:例如延期、改签、跨城办事、临时任务等说明。
- 风险动作:提醒、人工复核、要求补充说明、退回修改、禁止提交。
字段展示统一为:
```text
申报目的地[claim.destination_city]
明细发生地点[item.location_city]
交通票行程城市[receipt.transport_route_cities]
住宿发票城市[receipt.hotel_city]
出差开始日期[trip.start_date]
出差结束日期[trip.end_date]
报销事由[claim.reason]
```
### C3. 可执行 JSON DSL
JSON DSL 应表达规则执行逻辑,而不是保存自然语言摘要。建议基本结构:
```json
{
"rule_id": "risk.travel.city_mismatch",
"version": "v1",
"scope": {
"business_stage": "reimbursement",
"expense_types": ["travel", "lodging"]
},
"required_fields": [
{
"label": "申报目的地",
"field": "claim.destination_city",
"source": "claim",
"required": true
}
],
"conditions": {
"all": [
{
"op": "in_scope",
"field": "expense.type",
"values": ["travel", "lodging"]
},
{
"op": "any_present",
"fields": [
"receipt.transport_route_cities",
"receipt.hotel_city",
"item.location_city"
]
},
{
"op": "none_match",
"left_fields": [
"receipt.transport_route_cities",
"receipt.hotel_city"
],
"right_fields": [
"claim.destination_city",
"item.location_city",
"trip.route_cities"
],
"matcher": "city_equivalent"
},
{
"op": "not_contains_any",
"field": "claim.reason",
"values": ["延期", "改签", "跨城办事", "临时任务", "绕行"]
}
]
},
"action": {
"risk_level": "high",
"risk_score": 76,
"decision": "review_required",
"message": "票据城市与申报目的地或行程城市不一致,且未说明合理原因。"
}
}
```
核心要求:
- 城市、日期、金额、人员、供应商等字段必须使用专门比较算子,不能退化成“关键词出现”。
- 复杂规则允许多层条件组合:`all``any``not``branch``exists``range``compare``semantic_contains`
- 例外说明可以使用语义包含,但只能影响“是否进入复核/降级/豁免”,不能替代结构化字段判断。
- DSL 生成后必须通过 schema 校验和执行器 dry-run。
### C4. 流程判断图
流程图不是编辑器,也不是自然语言插图。流程图必须由 JSON DSL 转换成 `flow_model`,再生成 SVG。
建议 `flow_model`
```json
{
"nodes": [
{
"id": "start",
"type": "start",
"title": "开始",
"description": "进入差旅住宿报销风险检查"
},
{
"id": "scope",
"type": "decision",
"title": "是否属于差旅住宿报销",
"fields": ["expense.type", "claim.business_stage"]
},
{
"id": "city_match",
"type": "decision",
"title": "票据城市是否匹配申报或行程城市",
"fields": [
"receipt.hotel_city",
"receipt.transport_route_cities",
"claim.destination_city",
"trip.route_cities"
]
},
{
"id": "hit",
"type": "risk",
"title": "命中高风险",
"description": "要求补充行程说明或退回修改"
}
],
"edges": [
{ "from": "start", "to": "scope", "label": "开始检查" },
{ "from": "scope", "to": "end_pass", "label": "否" },
{ "from": "scope", "to": "city_match", "label": "是" },
{ "from": "city_match", "to": "end_pass", "label": "是" },
{ "from": "city_match", "to": "hit", "label": "否" }
]
}
```
流程图展示要求:
- 详情页左侧为文字流程解释,右侧为“流程图”。
- 判断分支用“是 / 否 / 通过 / 不通过 / 缺失 / 存在”等明确标签。
- 风险命中框使用风险等级颜色:低风险蓝色,中风险橙色,高风险红色,极高风险深红色。
- 普通节点保持 SaaS 白底、细边框、低饱和样式,不能整张图都染成风险色。
- 图只做展示,不响应拖拽、编辑、缩放和节点点击。
- 节点数量超过 8 个时,需要自动压缩文字、合并说明节点或分页展示,避免图过大。
### C5. 测试命中路径
测试规则弹窗应展示三类信息:
1. 输入与识别结果
- 用户自然语言测试意图。
- 上传附件清单。
- OCR / 文档智能识别字段。
- Hermes 辅助规范化后的结构化字段。
2. 规则执行结果
- 是否进入适用范围。
- 每个判断节点的输入值、比较方式、判断结果。
- 命中的风险动作。
- 未命中的原因。
3. 流程图路径高亮
- 使用同一个 `flow_model`
- 本次执行走过的节点和边由执行器输出 `trace`
- 前端按 `trace` 高亮路径。
执行 trace 示例:
```json
{
"trace_id": "run_001",
"matched": true,
"risk_level": "high",
"risk_score": 76,
"steps": [
{
"node_id": "scope",
"result": true,
"inputs": {
"expense.type": "住宿费",
"claim.business_stage": "reimbursement"
}
},
{
"node_id": "city_match",
"result": false,
"inputs": {
"receipt.hotel_city": "北京",
"claim.destination_city": "上海",
"trip.route_cities": ["武汉", "上海"]
}
}
]
}
```
### C6. 规则修改与版本化
规则修改分三种:
- 未上线规则:允许创建者或 admin 直接编辑,保存后重新生成 DSL、流程图、评分和说明。
- 已上线规则:不允许直接覆盖,必须点击“创建修订版本”。
- 业务用户反馈:只能提交误判/漏判反馈,由管理员决定是否创建修订版本。
已上线规则修改流程:
```text
线上版本 active
创建修订版本 draft_revision
编辑自然语言 / 参数 / 附件要求
重新生成 JSON DSL + 流程图 + 评分
仿真测试通过
发布新版本
旧版本归档,新版本 active
```
版本记录必须包含:
- 修改人。
- 修改原因。
- 修改前后自然语言差异。
- 修改前后 DSL 差异。
- 测试报告。
- 发布时间。
- 是否替换线上版本。
## 方案设计
### 总体链路
```text
自然语言规则
字段本体召回与业务域约束
Hermes 生成语义计划 semantic_plan
语义计划校验与补全
生成 JSON DSL
Schema 校验 + 执行器 dry-run
风险评分 risk_score / risk_level
DSL 转 flow_model
flow_model 转 flow_diagram_svg
详情展示 + 仿真测试 + 上线执行
```
### 前端设计
涉及入口:
- `AuditRuleDialogs.vue`:新建风险规则表单,后续增加修订版本编辑入口。
- `AuditJsonRiskRuleDetail.vue`:详情页展示基本信息、测试状态、流程解释、流程图、操作按钮。
- `RiskRuleFlowDiagram.vue`:只负责展示 SVG 或由 `flow_model` 派生的静态图,不做编辑。
- `RiskRuleTestDialog.vue`:仿真测试窗口,展示输入识别、执行路径、测试报告。
- `auditViewRiskRuleModel.js` / `auditViewModel.js`:规则详情视图模型、列表字段和状态映射。
详情页建议结构:
```text
Topbar规则标题、状态、风险分数、风险等级、上线/启用状态
基本信息:费用领域、业务环节、附件要求、创建人、上线时间、最后操作、测试状态
判断流程:
左侧:文字流程解释
右侧:流程图
测试与版本:
最近测试报告
修订版本 / 历史版本
操作按钮
```
修改规则界面建议采用左右布局:
- 左侧:自然语言规则编辑、规则标题、费用领域、附件要求。
- 右侧:系统解释预览,包括字段、本体映射、流程解释、风险分数。
- 底部:重新生成、保存草稿、测试规则、提交上线。
### 后端设计
已有相关模块应优先复用:
- `risk_rule_generation.py`:规则生成主流程。
- `risk_rule_generation_prompt.py`Hermes 提示词。
- `risk_rule_generation_ontology.py`:字段本体和费用领域约束。
- `risk_rule_generation_semantics.py`:自然语言语义解释。
- `risk_rule_generation_interpreter.py`:解释结果到 DSL。
- `risk_rule_scoring.py`:风险评分。
- `risk_rule_flow_diagram.py`:流程图 SVG 生成。
- `risk_rule_manifest_normalizer.py`:规则 manifest 规范化。
- `risk_rule_template_executor.py`:规则执行器。
- `agent_asset_risk_rule_testing.py`:规则测试、删除、发布、启用。
- `agent_asset_risk_rule_simulation.py`:仿真测试对话。
后端需要补齐的能力:
- 生成 `semantic_plan` 并持久化到 `config_json` 或版本内容中。
- 生成并持久化 `flow_model`,再生成 `flow_diagram_svg`
- 执行器输出 `trace`,用于测试解释和流程图高亮。
- 支持创建修订版本,避免直接覆盖 active 版本。
- 支持从常见模板创建规则,模板也走同一套生成和校验链路。
### 接口设计
建议新增或调整:
```text
POST /agent-assets/risk-rules/generate
根据自然语言创建生成任务,返回生成中资产。
POST /agent-assets/{asset_id}/risk-rules/regenerate
对草稿或修订版本重新生成 DSL、评分和流程图。
POST /agent-assets/{asset_id}/risk-rules/revisions
基于已上线规则创建修订版本。
PATCH /agent-assets/{asset_id}/risk-rules/draft
保存未上线规则或修订版本的编辑内容。
POST /agent-assets/{asset_id}/risk-rule-tests/simulate
独立仿真测试返回字段识别、执行结果、trace。
GET /agent-assets/{asset_id}/risk-rule-tests/latest
返回最近测试摘要。
POST /agent-assets/{asset_id}/publish
发布通过测试的规则版本。
```
### 数据设计
建议在风险规则版本内容或 `config_json` 中保留:
```json
{
"source_text": "用户输入的自然语言规则",
"semantic_plan": {},
"dsl": {},
"flow_model": {},
"flow_diagram_svg": "<svg>...</svg>",
"flow_explanation": [],
"risk_score": 76,
"risk_level": "high",
"required_attachment": true,
"required_fields": [],
"last_operation": {
"action": "publish",
"actor": "admin",
"at": "2026-05-30T10:00:00+08:00"
}
}
```
测试记录保留:
```json
{
"test_type": "simulation",
"input_text": "我去北京出差 3 天,上传武汉到上海车票",
"attachments": [],
"recognized_fields": {},
"normalized_fields": {},
"execution_result": {},
"trace": {},
"passed": true,
"tester": "admin",
"tested_at": "2026-05-30T10:10:00+08:00"
}
```
## 算法与公式
### 风险评分
风险评分由模型辅助判断,但必须结构化输出。建议使用可解释加权模型:
$$
score = \min(100, base + \sum_{i=1}^{n} w_i x_i + c + e)
$$
变量说明:
- $base$:业务领域基础风险分。预算、发票、付款类通常高于普通提示类。
- $x_i$:风险因子是否存在或强度,例如金额影响、附件缺失、字段冲突、越权、历史重复。
- $w_i$:风险因子权重。
- $c$:复杂度修正,例如多字段交叉、跨单据、跨时间窗口、跨附件识别。
- $e$:例外说明修正。存在合理说明时可降低,但不能直接清零。
等级映射:
- 0-30低风险。
- 31-60中风险。
- 61-80高风险。
- 81-100极高风险。
### 流程复杂度控制
为了避免流程图过大,建议定义流程复杂度:
$$
complexity = node_count + 0.5 \times edge_count + branch_count
$$
处理规则:
- `complexity <= 12`:单图展示。
- `12 < complexity <= 20`:合并说明节点,保留关键判断。
- `complexity > 20`:详情页展示主流程,测试弹窗展示完整 trace。
## 测试方案
### 单元测试
- 语义计划生成:复杂差旅城市规则不能退化为关键词判断。
- DSL schema 校验:缺字段、非法算子、空 action 必须失败。
- 执行器:城市匹配、日期范围、金额阈值、附件缺失、例外说明。
- 流程转换:同一 DSL 生成稳定的 `flow_model` 和 SVG。
- 风险评分:低/中/高/极高边界分数。
### 接口测试
- 新建规则返回生成中资产。
- 生成完成后包含 `dsl``flow_model``flow_diagram_svg``risk_score`
- 仿真测试返回 `recognized_fields``normalized_fields``trace`
- 未测试通过的规则不能发布。
- 已上线规则创建修订版本,不覆盖线上版本。
### 前端测试
- 新建弹窗不再选择风险等级。
- 详情页展示风险分数、流程解释、流程图。
- 流程图不可点击、不可拖拽、无工具栏。
- 测试弹窗显示字段识别结果和判断路径。
- 已上线规则只能创建修订版本修改。
### 容器验证
后续开发验证默认在 Docker 容器内执行:
```bash
docker exec x-financial-main sh -lc "cd /app/server && pytest <target> --timeout=60"
docker exec x-financial-main sh -lc "cd /app/web && npm run build"
```
### 本轮落地结果
已落地接口:
- `GET /agent-assets/risk-rules/templates`:返回预算、票据、差旅、招待、采购/AP、企业卡、通用模板分组包含默认自然语言、字段清单、附件要求和 DSL 样例。
- `PATCH /agent-assets/{asset_id}/risk-rules/draft`:编辑未上线风险规则草稿。
- `POST /agent-assets/{asset_id}/risk-rules/revisions`:为已上线规则创建修订草稿。
- `POST /agent-assets/{asset_id}/risk-rules/regenerate`:重新生成 DSL、流程图、风险评分和业务说明。
- `POST /agent-assets/{asset_id}/risk-rules/feedback``GET /agent-assets/{asset_id}/risk-rules/feedback`:记录和查看误判/漏判反馈。
关键文件:
- 后端模板库与契约:`risk_rule_template_catalog.py``agent_asset.py``agent_asset_risk_rules.py`
- 后端生成、修订、发布、反馈、仿真:`risk_rule_generation*``agent_asset_risk_rule_revision.py``agent_asset_risk_rule_regeneration.py``agent_asset_risk_rule_publish.py``agent_asset_risk_rule_feedback.py``agent_asset_risk_rule_simulation.py`
- 前端新建、详情、测试:`AuditRuleDialogs.vue``AuditJsonRiskRuleDetail.vue``RiskRuleFlowDiagram.vue``RiskRuleTestDialog.vue``auditViewDetailTopBar.js``useAuditRiskRuleActions.js``useAuditAssetData.js`
- 测试:`test_risk_rule_template_catalog.py``test_risk_rule_feedback.py``test_risk_rule_revision_endpoints.py``test_risk_rule_explainability.py``risk-rule-detail-experience.test.mjs`
已执行验证命令:
```bash
docker exec x-financial-main bash -lc "cd /app/server && timeout 60 /tmp/x-financial-server-venv/bin/python -m pytest tests/test_risk_rule_template_catalog.py tests/test_openapi_schema.py -q"
docker exec x-financial-main bash -lc "cd /app/server && timeout 60 /tmp/x-financial-server-venv/bin/python -m pytest tests/test_risk_rule_feedback.py tests/test_risk_rule_revision_endpoints.py tests/test_openapi_schema.py -q"
docker exec x-financial-main bash -lc "cd /app/web && timeout 60 node --test tests/risk-rule-detail-experience.test.mjs"
docker exec x-financial-main bash -lc "cd /app/web && timeout 60 npm run build"
```
## 指标与验收
- [A1] 新建复杂差旅规则后,详情页流程解释不能出现“检查是否包含风险关键词”这类错误表达。
- [A2] 详情页流程图与 JSON DSL 条件数量、分支方向、命中动作一致。
- [A3] 仿真测试能显示票据识别字段,并说明为什么命中或未命中。
- [A4] 同一条测试样例的执行 trace 可以高亮流程图路径。
- [A5] 已上线规则修改时不会改变当前线上执行结果,只有发布修订版本后才替换。
- [A6] 低、中、高、极高风险都能由评分模型产出,不应默认集中在中高风险。
- [A7] 前端构建通过,后端定向测试 60s 内完成。
## 风险与开放问题
- LLM 语义理解仍可能出错,因此必须有 schema 校验、执行器 dry-run、详情解释和仿真测试兜底。
- 字段本体不完整会限制规则表达,需要持续扩展费用、票据、预算、采购/AP 字段。
- 复杂规则可能产生过大的流程图,需要主流程和完整 trace 分层展示。
- 老规则没有 `semantic_plan``flow_model`,需要兼容展示并允许重新生成。
- 常见规则模板要避免写成定制逻辑。模板只能提供默认文本、字段和 DSL 样例,最终仍走通用生成链路。
当前仍需持续演进的点:
- 企业卡、采购/AP、预算场景的字段本体还偏少后续应补充企业卡交易流水、供应商、采购订单、合同、预算期间等字段。
- 复杂规则的准确性仍依赖 Hermes 语义计划质量,执行前必须继续保留 DSL validator、执行器 dry-run 和仿真测试。
- 模板库只作为规则编写入口的业务参考,不作为规则执行捷径;新增模板时必须同时提供 DSL 样例和 validator 测试。
## 实现确认
当前实现仍围绕“解释图和执行逻辑一致”推进:自然语言先经字段本体和语义计划形成受控 JSON DSL详情页流程图、文字流程解释、测试 trace、上线版本均围绕同一份 DSL 展示和执行,没有新增流程图编辑器或绕过规则执行器的判断链路。

View File

@@ -0,0 +1,96 @@
# 风险规则可解释流程判断改造 TODO
## 使用规则
- 每个 TODO 对应 `CONCEPT.md` 的目标、能力或验收点。
- 只有真实完成并通过相应验证后,才能把 `[ ]` 改成 `[x]`
- 如果实现中发现需求变化,先更新 `CONCEPT.md`,再调整本 TODO。
- 后端和构建验证默认在 Docker 容器 `x-financial-main``/app` 下执行。
## 1. 调研与边界
- [x] [CONCEPT: 背景与问题] 梳理当前风险规则生成链路,记录 `risk_rule_generation.py``risk_rule_template_executor.py` 的真实调用关系。证据:`CONCEPT.md` 后端设计与本轮落地结果记录生成、DSL validator、执行器、流程图、仿真测试链路。
- [x] [CONCEPT: 前端设计] 梳理详情页、新建弹窗、测试弹窗当前字段来源,记录 `AuditRuleDialogs.vue``AuditJsonRiskRuleDetail.vue``RiskRuleTestDialog.vue` 的改造点。证据:`CONCEPT.md` 本轮落地结果列出三个组件及对应职责,`risk-rule-detail-experience.test.mjs` 覆盖关键接线。
- [x] [CONCEPT: 数据设计] 确认 `AgentAssetRead`、版本内容、`config_json` 中已有字段,确定 `semantic_plan``flow_model``flow_diagram_svg` 的落点。证据:`AgentAssetRead` 返回 `latest_test_summary`,版本 JSON metadata 保存 `semantic_plan`/`flow_model`/`flow_diagram_svg`,生成测试覆盖。
- [x] [CONCEPT: 非目标] 明确本期不做流程图编辑器,不增加拖拽、缩放、节点编辑能力。证据:`RiskRuleFlowDiagram.vue` 只渲染静态 SVG/文字说明,无编辑、拖拽、缩放入口;前端回归测试断言不存在 zoom 按钮。
## 2. 语义计划与 DSL 契约
- [x] [CONCEPT: C2] 定义 `semantic_plan` schema包含规则意图、适用范围、字段本体映射、判断步骤、例外条件和风险动作。证据`risk_rule_explainability.py` 产出 `semantic_plan``test_risk_rule_explainability.py` 已验证。
- [x] [CONCEPT: C3] 定义 JSON DSL schema补齐城市、日期、金额、附件、语义说明等通用算子。证据`risk_rule_dsl_validator.py` 定义受控 DSL 校验,`risk_rule_generation_interpreter.py` 补充 `numeric_compare``risk_rule_template_executor.py` 支持日期、字段集合、附件存在性、文本例外和数值比较算子。
- [x] [CONCEPT: C3] 增加 DSL validator禁止复杂字段判断退化为“风险关键词匹配”。证据`validate_risk_rule_draft` 会将城市一致性关键词规则改写为结构化比较,将预算金额关键词规则改写为 `composite_rule_v1``test_risk_rule_dsl_validator.py` 覆盖。
- [x] [CONCEPT: C3] 为差旅城市不一致、住宿日期越界、预算阈值、重复发票各准备一条 DSL 样例。证据:新增 `risk_rule_dsl_examples.py`,并通过 `test_risk_rule_dsl_examples.py` 覆盖四类样例的 validator 与执行器命中/未命中回归。
- [x] [CONCEPT: C2] 字段展示统一为 `中文[英文]` 格式,并复用字段本体解释。证据:`risk_rule_explainability.py``semantic_plan.required_fields.display` 使用字段本体生成 `label[key]`
## 3. Hermes 生成链路
- [x] [CONCEPT: 总体链路] 调整 `risk_rule_generation_prompt.py`,要求 Hermes 先输出 `semantic_plan`,再输出 DSL。证据提示词 `required_json_shape` 改为 `{ semantic_plan, dsl }``test_prompt_requires_semantic_plan_then_dsl` 验证。
- [x] [CONCEPT: C2] 在提示词中明确:城市、日期、金额、票据关系必须用结构化比较,不允许用关键词替代。证据:`risk_rule_generation_prompt.py` 补充 `numeric_compare` 和预算金额不得关键词匹配的 guardrail。
- [x] [CONCEPT: 后端设计] 在 `risk_rule_generation_semantics.py` 或解释层补齐语义计划解析与错误返回。证据:`risk_rule_generation_semantic_plan.py` 解析 `{ semantic_plan, dsl }` 包装并保留 `metadata.model_semantic_plan`;后台生成失败写入 `generation_error``last_operation=generation_failed`,容器内 `test_risk_rule_generation_failure.py` 与语义计划测试通过。
- [x] [CONCEPT: 后端设计] 在 `risk_rule_generation_interpreter.py` 中从 `semantic_plan` 生成标准 DSL。证据新增 `build_dsl_from_semantic_plan`,当 Hermes 仅返回 `semantic_plan` 时生成 `composite_rule_v1` 草稿,再由 DSL validator 基于字段本体规范成受控条件;`test_semantic_plan_only_response_can_generate_standard_dsl` 通过。
- [x] [CONCEPT: 指标与验收] 增加复杂差旅规则生成测试,确认判断依据不是关键词匹配。证据:`test_generate_complex_travel_route_rule_uses_formula_not_keyword_match` 验证复杂差旅规则生成后为结构化城市一致性规则,且 `condition_summary` 不含“风险关键词”;容器内 `test_risk_rule_generation.py` 通过。
## 4. 流程模型与 SVG
- [x] [CONCEPT: C4] 定义 `flow_model` schema包含 nodes、edges、字段引用、分支标签和风险节点。证据`risk_rule_explainability.py` 产出 `flow_model`,生成测试验证 nodes/source/metadata 同步。
- [x] [CONCEPT: C4] 修改 `risk_rule_flow_diagram.py`,改为从 DSL 或 `flow_model` 生成 SVG。证据新增 `build_risk_rule_flow_diagram_spec`,优先从 `flow_model.nodes` 生成图形 spec缺失时回退 `params.conditions``test_flow_diagram_spec_prefers_flow_model_nodes` 通过。
- [x] [CONCEPT: C4] 保持 Style 7 / OpenAI Official 风格:白底、细边框、低饱和、风险节点单点强调。证据:`RiskRuleFlowDiagramRenderer` 输出白底、细边框、低饱和风险色,既有 `test_risk_rule_generation.py` 校验高风险红色、无旧绿色和无阴影滤镜。
- [x] [CONCEPT: 算法与公式] 实现流程复杂度控制,节点过多时压缩主流程。证据:`_condition_lines_from_flow_nodes` 将超过 4 个判断节点压缩为摘要,`test_flow_diagram_spec_compresses_too_many_decision_nodes` 覆盖。
- [x] [CONCEPT: C4] 为老规则缺少 `flow_model` 的情况保留默认静态图兜底。证据:`build_risk_rule_flow_diagram_spec``flow_model` 缺失时使用 DSL/metadata 生成 spec`test_flow_diagram_spec_falls_back_to_dsl_when_flow_model_missing` 通过。
## 5. 执行器 trace 与仿真测试
- [x] [CONCEPT: C5] 修改 `RiskRuleTemplateExecutor`,输出每个判断节点的 trace。证据新增 `evaluate_with_trace`,仿真测试返回 `trace.steps``path_node_ids`
- [x] [CONCEPT: C5] 仿真测试统一在“用户点击运行”后处理附件和文本,不允许上传后立即判断。证据:`RiskRuleTestDialog.vue``handleFileChange` 只把附件加入待发送列表,`sendMessage` 才调用 `recognizeTemporaryFiles``simulateRiskRuleTest`;容器内 `npm run build` 通过。
- [x] [CONCEPT: C5] 测试结果中展示 OCR 原始字段、Hermes 规范化字段、执行器实际输入字段。证据:`AgentAssetRiskRuleSimulationRead` 新增 `ocr_raw_fields``hermes_normalized_fields``executor_input_fields``RiskRuleTestDialog.vue` 展示字段流水线;容器内 `test_risk_rule_explainability.py``test_risk_rule_generation.py` 通过。
- [x] [CONCEPT: C5] 测试弹窗展示命中路径、未命中原因和最终风险动作。证据:`RiskRuleTestDialog.vue` 展示“执行路径”,`riskRuleTestDialogDisplay.js` 格式化 trace。
- [x] [CONCEPT: C5] trace 中的 `node_id` 必须能映射到流程图节点。证据:`flow_model` 使用条件 id 作为节点 id`risk_rule_execution_trace.py` 输出同名 `node_id`
## 6. 规则修改与版本化
- [x] [CONCEPT: C6] 未上线规则支持编辑标题、费用领域、附件要求和自然语言描述。证据:新增 `AgentAssetRiskRuleRevisionService.update_unpublished_draft``PATCH /agent-assets/{asset_id}/risk-rules/draft`,容器内 `test_risk_rule_revision_endpoints.py` 覆盖返回字段。
- [x] [CONCEPT: C6] 已上线规则新增“创建修订版本”,不直接覆盖 active 版本。证据:新增 `AgentAssetRiskRuleRevisionService.create_revision_draft``POST /agent-assets/{asset_id}/risk-rules/revisions`,测试验证 `published_version` 保持不变且 `working_version` 进入修订版本。
- [x] [CONCEPT: C6] 修订版本保存后重新生成 DSL、流程图、风险评分和业务说明。证据新增 `AgentAssetRiskRuleRegenerationService``POST /agent-assets/{asset_id}/risk-rules/regenerate`,草稿/修订草稿都会重新生成 JSON DSL、`flow_diagram_svg`、风险评分和版本 Markdown容器内 `test_regenerate_revision_draft_keeps_active_document_unchanged` 通过。
- [x] [CONCEPT: C6] 发布修订版本时归档旧版本,并记录修改人、修改原因和测试报告。证据:新增 `AgentAssetRiskRulePublishMixin`,发布修订时将旧 `rule_document` 写入 `revision_history.previous_rule_document`,切换新 JSON 文件并写入 `last_operation=publish_revision`;容器内 `test_publish_regenerated_revision_replaces_online_document` 通过。
- [x] [CONCEPT: C6] 普通用户误判/漏判反馈进入规则反馈记录,不直接修改规则。证据:新增 `agent_asset_rule_feedback` 模型、`POST/GET /agent-assets/{asset_id}/risk-rules/feedback`、前端服务方法;容器内 `test_risk_rule_feedback.py`、规则回归和 `npm run build` 通过。
## 7. 常见费控规则模板库
- [x] [CONCEPT: C1] 增加“从常见规则模板创建”入口。证据:`AuditRuleDialogs.vue` 新建风险规则弹窗新增常见规则模板选择,选择后预填标题、附件要求、业务环节、费用领域和自然语言。
- [x] [CONCEPT: C1] 模板按预算、票据、差旅、招待、采购/AP、企业卡、通用分组。证据新增 `risk_rule_template_catalog.py``GET /agent-assets/risk-rules/templates` 返回 7 个分组;容器内 `test_risk_rule_template_catalog.py` 通过。
- [x] [CONCEPT: C3] 每个模板提供默认自然语言、字段清单、附件要求和 DSL 样例。证据:模板接口返回 `natural_language``fields``requires_attachment``dsl_example`;容器内测试逐个调用 DSL validator 验证通过。
- [x] [CONCEPT: 非目标] 模板不得绕过通用生成链路,不写定制校准器。证据:前端模板只预填 `riskRuleCreateForm`,提交仍走 `generateRiskRuleAsset`;无新增定制校准器,容器内 `npm run build` 通过。
## 8. 前端详情与交互
- [x] [CONCEPT: 前端设计] 详情页 topbar 展示规则标题、状态、风险分数、风险等级、上线/启用状态。证据:`auditViewDetailTopBar.js` 为风险规则详情输出风险分、风险等级、规则状态、上线状态、启用状态 KPI容器内 `npm run build` 通过。
- [x] [CONCEPT: C4] 判断流程区域改成左侧文字流程解释、右侧流程图。证据:`RiskRuleFlowDiagram.vue` 使用左侧 `risk-rule-flow-explainer` 和右侧 `risk-rule-flow-visual` 的两栏布局;容器内 `npm run build` 通过。
- [x] [CONCEPT: C4] 流程图标题固定为“流程图”,高度与“流程解释”标题对齐。证据:`RiskRuleFlowDiagram.vue` 使用统一 `risk-rule-section-title`,右侧标题固定为“流程图”;容器内 `npm run build` 通过。
- [x] [CONCEPT: C5] 测试弹窗展示字段识别结果、规范化字段、判断路径和测试报告。证据:`RiskRuleTestDialog.vue` 展示字段流水线、执行路径和右侧测试报告摘要;容器内 `cd /app/web && npm run build` 通过。
- [x] [CONCEPT: C6] 已上线规则详情展示“创建修订版本”,草稿规则展示“编辑规则”。证据:`AuditView.vue` 底部动作区按规则状态展示按钮,`AuditRuleDialogs.vue` 提供编辑/修订弹窗,`useAuditRiskRuleActions.js` 调用草稿编辑与修订接口;容器内 `cd /app/web && npm run build` 通过。
- [x] [CONCEPT: 指标与验收] 列表和详情状态刷新不能造成页面闪烁。证据:`useAuditAssetData.loadSelectedAssetDetail` 增加 `{ silent: true }` 静默刷新,规则保存、送审、审核、上线、回退和版本操作均改为静默刷新;容器内 `npm run build` 通过。
## 9. 后端接口与权限
- [x] [CONCEPT: 接口设计] 实现或调整 `POST /agent-assets/{asset_id}/risk-rules/revisions`。证据:新增独立路由 `agent_asset_risk_rules.py`,容器内 `test_create_risk_rule_revision_endpoint_keeps_active_version` 通过。
- [x] [CONCEPT: 接口设计] 实现或调整 `PATCH /agent-assets/{asset_id}/risk-rules/draft`。证据:新增独立路由 `agent_asset_risk_rules.py`,容器内 `test_update_risk_rule_draft_endpoint_updates_unpublished_rule` 与已上线阻断用例通过。
- [x] [CONCEPT: 接口设计] `POST /agent-assets/{asset_id}/risk-rules/regenerate` 返回生成状态和错误详情。证据:独立路由 `agent_asset_risk_rules.py` 已接入重生成接口,成功返回 `AgentAssetRead.config_json.generation_status`/`revision_draft.generation_status`,接口用例 `test_regenerate_risk_rule_endpoint_returns_updated_detail` 通过。
- [x] [CONCEPT: 接口设计] 仿真测试接口返回 `recognized_fields``normalized_fields``execution_result``trace`。证据:`AgentAssetRiskRuleSimulationRead` 新增 `normalized_fields``trace`,仿真测试覆盖返回值。
- [x] [CONCEPT: 用户与场景] 普通财务人员只能编辑未上线/修订草稿admin 才能删除和测试,管理员按现有权限上线/下线。证据:路由依赖使用 `RuleEditorUser``RuleReviewerUser``PlatformAdminUser` 分层,`test_risk_rule_revision_endpoints.py` 覆盖 finance 新建/测试阻断、manager 删除阻断和 manager 启停入口。
- [x] [CONCEPT: 数据设计] 所有操作写入 `last_operation`,用于详情页“最后操作”展示。证据:生成、后台生成、草稿编辑、创建修订、重新生成、发布/下线、测试确认等风险规则服务均写入 `config_json.last_operation`,前端 `AuditJsonRiskRuleDetail.vue` 展示 `lastOperationLabel`
## 10. 测试与验证
- [x] [CONCEPT: 测试方案] 后端补充语义计划、DSL validator、执行器 trace、流程图转换单元测试。证据`test_risk_rule_explainability.py` 覆盖语义计划、flow_model、trace`test_risk_rule_dsl_validator.py` 覆盖 DSL validator 与 `numeric_compare` 执行;容器内相关测试通过。
- [x] [CONCEPT: 测试方案] 后端补充修订版本接口和发布替换接口测试。证据:`test_risk_rule_revision_service.py` 覆盖草稿编辑、创建修订、修订重生成和发布替换;`test_risk_rule_revision_endpoints.py` 覆盖草稿编辑、创建修订和重生成接口;容器内相关测试通过。
- [x] [CONCEPT: 测试方案] 前端补充详情页流程展示、测试弹窗字段展示、修订版本按钮状态测试。证据:新增 `risk-rule-detail-experience.test.mjs` 覆盖 topbar KPI、左文右图流程、字段流水线和修订按钮容器内 `node --test tests/risk-rule-detail-experience.test.mjs` 通过。
- [x] [CONCEPT: 容器验证] 在容器执行后端定向测试,单个命令设置 60s 超时。证据:`/tmp/x-financial-server-venv/bin/python -m pytest tests/test_risk_rule_explainability.py -q``test_risk_rule_composite_generation.py -q``test_risk_rule_generation.py -q` 均通过。
- [x] [CONCEPT: 容器验证] 在容器执行 `cd /app/web && npm run build`。证据:容器 `/app/web` 构建通过。
- [x] [CONCEPT: 指标与验收] 用“武汉到上海票据 + 北京出差 3 天”样例验证城市不一致规则必须命中或给出明确不命中原因。证据:`test_simulation_returns_execution_trace_for_ticket_city_mismatch` 验证命中并返回 trace。
- [x] [CONCEPT: 指标与验收] 用预算阈值、重复发票、住宿日期越界、招待人均超标样例做回归。证据:`risk_rule_dsl_examples.py` 已包含预算阈值、重复发票、住宿日期越界、招待人均超标样例,`test_risk_rule_dsl_examples.py` 在容器内 7 passed。
## 11. 文档收尾
- [x] [CONCEPT: 指标与验收] 开发完成后补充实际接口、文件和测试命令结果。证据:`CONCEPT.md` 新增“本轮落地结果”,列出接口、关键文件和容器验证命令。
- [x] [CONCEPT: 风险与开放问题] 记录暂未解决的字段本体缺口和复杂规则降级策略。证据:`CONCEPT.md` 风险与开放问题补充企业卡、采购/AP、预算字段本体缺口和 DSL validator/dry-run/仿真兜底策略。
- [x] [CONCEPT: 功能一句话] 确认最终实现没有偏离“解释图和执行逻辑一致”的核心目标。证据:`CONCEPT.md` 新增“实现确认”明确自然语言、字段本体、JSON DSL、流程图、测试 trace 和上线版本围绕同一 DSL。

View File

@@ -1,139 +0,0 @@
# 差旅报销风险管控标准(模拟版)
## 1. 目的
本标准用于约束个人报销中的差旅类单据审核,覆盖以下三类核心风险:
- 行程闭环风险:出发地、目的地、返程地之间是否形成合理链路。
- 票据地点一致性风险:酒店、交通票据与申报目的地是否一致。
- 差标超限风险:员工职级对应的交通舱位、火车席别、住宿金额是否超标。
本标准先以模拟规则落地到系统,用于 AI 验审与直属领导审批前的自动筛查。
## 2. 适用范围
- 报销主类型为 `travel / hotel / transport` 的单据。
- 或者明细附件识别出 `flight_itinerary / train_ticket / hotel_invoice / taxi_receipt / parking_toll_receipt` 的单据。
## 3. 基础定义
### 3.1 目的地
按以下优先级确定本次差旅的“主目的地”:
1. 用户在报销表单中填写的业务地点 `claim.location`
2. 长途交通票据终点城市
3. 酒店票据识别出的酒店所在城市
### 3.2 行程闭环
满足以下任一条件,视为形成合理闭环:
- 单程票据终点与申报目的地一致。
- 多段票据按时间顺序首尾衔接。
- 最后一段票据返回首段出发城市。
### 3.3 合理例外说明
若出现多城市出差、中转、改签、异地返程、展会高峰导致超标等情况,用户必须在报销事由或费用说明中体现原因。示例关键词:
- `中转`
- `转机`
- `经停`
- `改签`
- `多地出差`
- `客户临时变更`
- `展会高峰`
- `协议酒店满房`
- `无直达`
未说明时,系统按高风险处理并退回待补充。
## 4. 风险规则矩阵
### 4.1 行程闭环规则
- 若存在两段及以上长途交通票据,相邻两段的 `上一段终点城市``下一段起点城市` 必须一致。
- 若最终到达城市既不是申报目的地,也不是首段出发城市,则判定为高风险。
- 若识别到多个目的地城市,但事由中未说明多地出差、中转或改签原因,则判定为高风险。
处理方式:
- `高风险`:退回待补充。
- `中风险`:允许流转,但要求直属领导重点复核。
### 4.2 酒店地点一致性规则
- 酒店票据识别出的城市,必须属于以下集合之一:
- 申报目的地
- 长途交通票据中的目的地城市
- 长途交通票据中的返程前停留城市
- 若酒店城市与主目的地、交通链路均不一致,则判定为高风险。
处理方式:
- `高风险`:退回待补充,要求说明异地住宿原因或更换票据。
### 4.3 职级差旅标准
#### 4.3.1 城市分级
- 一线:`北京 / 上海 / 广州 / 深圳`
- 新一线 / 重点城市:`杭州 / 南京 / 苏州 / 武汉 / 成都 / 重庆 / 西安 / 天津 / 宁波 / 厦门 / 青岛 / 长沙`
- 其他城市:除以上外的默认城市
#### 4.3.2 住宿标准(元 / 晚)
| 职级带 | 一线 | 重点城市 | 其他城市 |
| --- | ---: | ---: | ---: |
| P1-P3 | 450 | 380 | 320 |
| P4-P5 | 550 | 480 | 380 |
| P6-P7 | 700 | 620 | 520 |
| M1-M2 | 900 | 820 | 720 |
| M3 及以上 / D 序列 | 1200 | 1000 | 900 |
说明:
- 若票据中能识别出 `X 晚 / X 间夜`,系统按 `总金额 / 间夜数` 计算每晚金额。
- 若无法识别间夜数,默认按 1 晚处理。
#### 4.3.3 交通标准
| 职级带 | 飞机 | 火车 / 高铁 |
| --- | --- | --- |
| P1-P3 | 经济舱 | 二等座 / 硬卧 |
| P4-P5 | 经济舱 | 二等座 / 硬卧 |
| P6-P7 | 超级经济舱及以下 | 一等座 / 软卧及以下 |
| M1-M2 | 商务舱及以下 | 商务座及以下 |
| M3 及以上 / D 序列 | 不做系统硬限制,仍保留人工复核 |
### 4.4 差标超限处理
- 超住宿标准且无说明:`高风险`
- 超住宿标准但有说明:`中风险`
- 飞机舱位或高铁席别超过职级标准且无说明:`高风险`
- 飞机舱位或高铁席别超过职级标准但有说明:`中风险`
## 5. 系统落地口径
### 5.1 票据识别字段
系统优先使用以下字段做判断:
- `route`
- `merchant_name`
- `amount`
- `date`
- OCR 原文中的舱位、席别、间夜数、城市名
### 5.2 AI 验审动作
- 高风险:提交前拦截,状态切回 `待补充`
- 中风险:允许进入直属领导审批,并附带风险标记
- 低风险 / 通过:正常流转
## 6. 当前实现边界
- 城市识别先按常见出差城市做匹配,未覆盖全国全部区县。
- 住宿标准与交通标准为模拟版,可后续迁移到任务规则中心做可配置化。
- 本文档为当前开发阶段的执行依据,后续若规则中心启用动态配置,应以规则中心版本为准。

View File

@@ -1,453 +0,0 @@
# 规则版本中心 UI 方案
## 1. 背景
当前“任务规则中心 > 财务规则 > 公司差旅费报销规则”已经具备:
- 在线 Excel 编辑
- 工作版本 / 线上版本分离
- 最近 5 个版本展示
- 审核、上线、恢复能力
但页面仍然存在一个明显问题:
**版本治理能力已经有了,用户却很难第一眼看见。**
当前版本列表更像“历史记录”,不是一个明确的“版本操作中心”。
用户无法快速判断:
1. 当前真正生效的是哪个版本
2. 当前正在编辑的是哪个版本
3. 从哪里进入版本切换
4. 从哪里发起版本对比
5. 某个版本经历了哪些流转动作
因此,需要把现有“版本列表”升级为一个真正可用的 **版本中心**
---
## 2. 设计目标
### 2.1 用户一眼能看懂
进入规则详情页后,用户无需点击就能立即识别:
- 当前线上版本
- 当前工作版本
- 是否存在未上线工作稿
- 最近版本是否处于待审 / 已通过 / 已驳回状态
### 2.2 关键操作显性化
以下操作不能再隐藏在不明显的位置:
- 切换查看版本
- 与线上版本对比
- 查看完整流转
- 从历史版本恢复
### 2.3 保持 OnlyOffice 是主角
该页面的核心仍然是 Excel 规则表。
版本中心必须增强治理能力,但不能把主表格压缩成附属内容。
---
## 3. 推荐方案
采用:
> **左侧 OnlyOffice 主工作区 + 右侧版本中心 + 顶部显性入口 + 抽屉式详情**
这是比“单独开二级页签”更适合当前页面的方案,因为用户经常需要:
- 一边看表
- 一边知道自己看的是什么版本
- 一边进入版本对比或恢复
---
## 4. 页面整体布局
```text
┌────────────────────────────────────────────────────────────────────┐
│ 标题区:公司差旅费报销规则 │
│ 线上版本 v1.0.5 已上线 工作版本 v1.0.6 待审核 │
│ [下载 Excel] [上传表格] [版本对比] [查看流转] │
├───────────────────────────────────────────────┬────────────────────┤
│ │ 版本中心 │
│ │ │
│ │ ┌──────────────┐ │
│ │ │ 线上版本 │ │
│ │ │ v1.0.5 │ │
│ │ └──────────────┘ │
│ OnlyOffice │ ┌──────────────┐ │
│ 规则表主工作区 │ │ 工作版本 │ │
│ │ │ v1.0.6 │ │
│ │ └──────────────┘ │
│ │ │
│ │ 最近版本 │
│ │ v1.0.6 待审核 │
│ │ v1.0.5 已上线 │
│ │ v1.0.4 历史版本 │
│ │ │
│ │ 最近流转 │
│ │ [查看完整流转] │
└───────────────────────────────────────────────┴────────────────────┘
```
---
## 5. 顶部操作区设计
顶部必须保留并强化四个动作:
| 按钮 | 用途 |
| --- | --- |
| 下载 Excel | 下载当前预览版本 |
| 上传表格 | 导入内容生成新工作稿 |
| 版本对比 | 打开对比抽屉 |
| 查看流转 | 打开流转抽屉 |
### 5.1 版本对比按钮
这是一级入口,不能只藏在版本列表里。
默认行为:
- 基准版本:当前线上版本
- 对比版本:当前工作版本
如果两者相同,则按钮仍可用,但进入后提示:
> 当前工作版本与线上版本一致,可选择其他历史版本进行比较。
### 5.2 查看流转按钮
用于进入当前规则的完整生命周期视图。
不应只展示审计日志,而要展示“版本业务履历”。
---
## 6. 右侧版本中心设计
### 6.1 顶部双版本卡片
```text
线上版本
v1.0.5
已上线
工作版本
v1.0.6
待审核
```
#### 设计目的
用户进入页面后,最先要知道的是:
- **谁在线上**
- **谁正在被编辑**
而不是先看一个无上下文的历史列表。
### 6.2 最近版本列表
每个版本项包含:
- 版本号
- 生命周期状态
- 创建时间
- 变更说明
- 操作入口
建议样式:
```text
v1.0.6 待审核
2026-05-18 09:12
补充出差补助标准
[查看] [与线上比]
v1.0.5 已上线
2026-05-18 08:40
新增补助页签
[查看]
v1.0.4 历史版本
2026-05-17 17:20
修正住宿标准
[查看] [恢复]
```
#### 规则
- `查看`:切换当前预览版本
- `与线上比`:直接以线上版本为基准进入对比
- `恢复`:仅高级管理人员可见
- 当前 `working_version` 不显示“恢复”
### 6.3 最近流转摘要
右侧版本中心底部展示最近 3 条流转:
```text
最近流转
09:12 曹笑竹 保存工作稿
09:25 曹笑竹 提交审核
10:08 顾承宇 审核通过
[查看完整流转]
```
---
## 7. 版本流转时间线设计
## 7.1 入口
两个入口:
1. 顶部 `查看流转`
2. 右侧版本中心底部 `查看完整流转`
## 7.2 容器
使用右侧宽抽屉,不使用小弹窗。
原因:
- 时间线内容会逐步增长
- 审核意见需要足够宽度展示
- 后续可能接入版本说明、操作人、来源版本
## 7.3 时间线内容
时间线按时间倒序或正序展示,推荐默认正序:
```text
● 2026-05-18 09:12
v1.0.6 工作稿创建
曹笑竹 保存工作稿
变更说明:补充出差补助标准
● 2026-05-18 09:25
提交审核
曹笑竹 提交当前工作版本
● 2026-05-18 10:08
审核通过
顾承宇:口径已核对,可上线
○ 待正式上线
```
如果版本来自恢复:
```text
● 基于 v1.0.3 恢复生成 v1.0.7
```
## 7.4 时间线事件类型
| 事件类型 | 说明 |
| --- | --- |
| `created` | 创建版本 |
| `submitted` | 提交审核 |
| `approved` | 审核通过 |
| `rejected` | 驳回 |
| `published` | 正式上线 |
| `restored` | 基于历史版本恢复 |
---
## 8. 版本差异对比设计
## 8.1 入口
版本对比必须有两个入口:
1. 顶部一级按钮:`版本对比`
2. 每个历史版本行内操作:`与线上比`
这样既满足“主动进入”,也满足“看到某个版本就顺手比较”。
## 8.2 容器
使用宽抽屉,推荐宽度:
- 桌面:页面宽度的 70% ~ 80%
- 小屏:全屏
不建议用普通弹窗,因为:
- Excel 差异需要足够展示宽度
- 版本选择器、摘要、表格都要共存
## 8.3 顶部区域
```text
版本对比
基准版本 [v1.0.5 已上线 ▼]
对比版本 [v1.0.6 待审核 ▼]
```
默认值:
- `baseVersion = published_version`
- `targetVersion = working_version`
## 8.4 差异摘要
优先先给决策信息,再给底层明细。
```text
差异摘要
- 修改 2 个工作表
- 新增 1 个工作表
- 修改 12 个单元格
- 删除 2 行
```
如果无差异:
```text
两个版本内容一致,没有发现表格差异。
```
## 8.5 差异详情
第一阶段优先支持 Excel 规则表:
| 工作表 | 位置 | 旧值 | 新值 | 类型 |
| --- | --- | --- | --- | --- |
| 出差补助标准 | B4 | 75 | 90 | 修改 |
| 差旅住宿费标准 | A106 | - | 新增城市 | 新增 |
后续可扩展:
- 仅看新增
- 仅看删除
- 仅看数值变化
- 按工作表筛选
## 8.6 对比结果的业务语气
不要把页面做成“程序员 diff 工具”。
它应该像制度审核页面:
- 先讲影响
- 再讲位置
- 最后给证据
---
## 9. 数据接口设计
## 9.1 时间线接口
建议新增:
```http
GET /agent-assets/{asset_id}/version-timeline
```
返回:
- 版本号
- 事件类型
- 操作人
- 操作时间
- 审核意见
- 来源版本(如有)
## 9.2 对比接口
建议新增:
```http
GET /agent-assets/{asset_id}/versions/compare?base_version=v1.0.5&target_version=v1.0.6
```
返回:
- 基准版本
- 对比版本
- 工作表差异摘要
- 单元格级差异明细
---
## 10. 视觉规范
### 10.1 颜色
沿用当前系统已有色彩,不引入新风格:
| 状态 | 建议色 |
| --- | --- |
| 已上线 | 绿色 |
| 工作稿 | 蓝色 |
| 待审核 | 橙色 |
| 已驳回 | 红色 |
| 历史版本 | 灰色 |
### 10.2 密度
- 右侧版本中心应为紧凑型信息面板
- 不要使用过大的卡片间距
- 不能明显压缩 OnlyOffice 主区域
### 10.3 交互反馈
- 可点击元素必须有 hover
- 当前预览版本必须有 active 高亮
- 抽屉打开后保留明确关闭按钮
- 恢复操作必须二次确认
---
## 11. 推荐实施顺序
### 第一阶段
1. 顶部新增 `版本对比``查看流转`
2. Excel 详情页改成:
- 左侧 OnlyOffice
- 右侧版本中心
3. 右侧展示:
- 线上版本
- 工作版本
- 最近 5 个版本
- 最近 3 条流转
### 第二阶段
1. 实现版本流转抽屉
2. 实现版本对比抽屉
3. 补齐真实后端接口
### 第三阶段
1. 增加更细的工作表筛选
2. 增加更多 diff 维度
3. 增加版本差异导出能力
---
## 12. 本次开发目标
本次开发直接完成以下内容:
1. 规则详情页出现明确的版本中心
2. 页面上出现明确的:
- `版本对比`
- `查看流转`
3. 最近版本列表增加:
- `查看`
- `与线上比`
- `恢复为工作稿`
4. 版本流转抽屉可用
5. 版本对比抽屉可用
6. 对比结果至少支持 Excel 表格的:
- 工作表新增 / 删除
- 单元格新增 / 删除 / 修改

View File

@@ -1,237 +0,0 @@
# 规则版本治理方案
## 1. 背景
当前“任务规则中心”的规则资产只有一个 `current_version` 指针。
它同时承担了三种含义:
1. 财务人员正在编辑的版本
2. 审核中的候选版本
3. 系统运行时真正生效的线上版本
这会直接带来三个问题:
- 财务人员一旦修改 Excel最新内容就会立刻成为 `current_version`,容易被误解为已经正式生效
- 审核、上线、回滚都围绕同一个指针转,权限边界不清晰
- 如果误上线,虽然能切换历史版本,但缺少“线上版本”和“工作版本”分离后的安全缓冲
## 2. 设计目标
这次改造要解决的不是“多存几个历史版本”,而是建立一套可长期使用的规则治理机制:
1. 财务人员可以编辑规则,但编辑结果默认只是草稿
2. 只有高级管理人员审核通过后,规则才能成为正式线上版本
3. 系统运行时只能读取正式线上版本,不能读取草稿
4. 前台要能清楚区分:
- 当前线上版本
- 当前工作版本
- 最近 5 个历史版本
5. 如果误操作上线,可以快速恢复,但恢复动作仍然要留下完整审计链
## 3. 核心模型
### 3.1 双指针版本模型
在规则资产上新增两个版本指针:
| 字段 | 含义 |
| --- | --- |
| `published_version` | 当前正式在线上生效的版本 |
| `working_version` | 当前最新的工作稿 / 待审稿 |
兼容策略:
- 现有 `current_version` 暂时保留,用于兼容历史代码
- 对规则资产来说,后续它只承担“当前工作版本”的兼容语义
- 运行时逻辑不再读取 `current_version`,而是优先读取 `published_version`
### 3.2 版本状态
不额外在版本表中硬存一套容易失真的状态,而是根据“版本指针 + 最新审核记录”动态推导:
| 条件 | 版本状态 |
| --- | --- |
| `version == published_version` | 已上线 |
| `version == working_version` 且无审核记录 | 草稿 |
| `version == working_version` 且最新审核为 `pending` | 待审核 |
| `version == working_version` 且最新审核为 `approved` | 已通过待上线 |
| `version == working_version` 且最新审核为 `rejected` | 已驳回 |
| 其他历史版本 | 历史版本 |
这样可以避免“版本状态”和“审核记录”两套数据互相打架。
## 4. 权限边界
| 角色 | 能力 |
| --- | --- |
| 财务人员 `finance` | 编辑工作稿、上传/导入 Excel、提交审核 |
| 高级管理人员 `manager` / `admin` | 审核通过、驳回、正式发布、恢复历史版本 |
| 其他普通员工 | 只读 |
### 4.1 财务人员
- 可以直接编辑当前 `working_version`
- 每次保存自动生成新版本,并把它设为新的 `working_version`
- 不能把草稿直接变成 `published_version`
### 4.2 高级管理人员
- 可以对 `working_version` 发起:
- 审核通过
- 驳回
- 正式发布
- 只有 `approved` 的工作版本才能发布
## 5. 发布与回滚流程
### 5.1 正常发布
1. 财务人员编辑并保存
2. 系统生成新版本,例如 `v1.0.6`
3. `working_version = v1.0.6`
4. 财务人员提交审核
5. 高级管理人员审核通过
6. 高级管理人员点击“正式上线”
7. `published_version = v1.0.6`
8. 系统运行时切换到新版本
### 5.2 驳回
1. 财务人员提交审核
2. 高级管理人员驳回
3. 当前工作版本保留,但状态显示为“已驳回”
4. 财务人员继续编辑,形成新的工作版本
### 5.3 恢复历史版本
不直接把 `published_version` 指回旧版本,而是采用“复制恢复”的方式:
1. 管理员在最近 5 个版本中选择一个历史版本
2. 系统基于该历史版本内容生成一个新的恢复版本,例如 `v1.0.7`
3. 新版本写入 `working_version`
4. 审核通过后再正式发布
这么做的好处:
- 不会破坏历史链路
- 每一次恢复都有明确的责任人与时间
- 既能快速回滚,又保留审计闭环
## 6. 版本保留策略
### 6.1 前台展示
- 详情页固定展示最近 5 个版本
- 每个版本显示:
- 版本号
- 状态
- 创建人
- 创建时间
- 变更说明
### 6.2 后台保存
后台不能机械地“只保留 5 个版本”,否则可能把关键线上版本挤掉。
建议策略:
1. 始终保留当前 `published_version`
2. 始终保留当前 `working_version`
3. 额外保留最近 5 个历史版本
这样既满足前台简洁,也能避免误删关键版本。
## 7. 前端交互
### 7.1 规则详情页顶部
展示两个醒目的版本标签:
- 当前线上版本
- 当前工作版本
如果两者不同,需要明确提示:
> 当前存在尚未上线的工作稿,系统运行仍以线上版本为准。
### 7.2 编辑区
- 财务人员看到“可编辑工作稿”
- 普通用户只读
- 管理员可编辑,但主要职责仍是审核与发布
### 7.3 版本区
最近 5 个版本中每条都显示状态:
- 已上线
- 草稿
- 待审核
- 已通过待上线
- 已驳回
- 历史版本
可执行操作:
- 查看
- 基于该版本恢复
- 对当前工作版本提交审核 / 审核 / 发布
## 8. 后端改造清单
1. `agent_assets`
- 新增 `published_version`
- 新增 `working_version`
2. 兼容旧数据
- 历史规则资产初始化时:
- `published_version = current_version`
- `working_version = current_version`
3. 版本保存
- 保存新版本后:
- 只更新 `working_version`
- `current_version` 同步为 `working_version` 以兼容旧逻辑
4. 审核
- 审核只针对 `working_version`
5. 发布
- 只允许把已审核通过的 `working_version` 推到 `published_version`
6. 运行时
- 只读取 `published_version`
7. 回滚
- 新增“基于历史版本恢复为新工作稿”的接口
## 9. 前端改造清单
1. 资产详情模型增加:
- `publishedVersion`
- `workingVersion`
- 每个历史版本的派生状态
2. 规则详情页展示:
- 当前线上版本
- 当前工作版本
- 最近 5 个版本
3. 操作权限拆分:
- finance编辑、上传、提交审核
- manager/admin审核、上线、恢复
4. OnlyOffice 编辑逻辑:
- 默认编辑工作版本
- 历史版本只读
5. 正式上线按钮:
- 只有工作版本已审核通过时可用
## 10. 本次实现边界
本轮优先完成以下能力:
1. 规则版本双指针
2. 财务角色可编辑工作稿
3. 正式上线只切换 `published_version`
4. 运行时只读取 `published_version`
5. 最近 5 个版本展示
6. 基于历史版本快速恢复为新工作稿
后续如需要,再继续补:
- 版本差异对比
- 审核意见流转面板
- 发布说明 / 审批单号
- 定时生效

Some files were not shown because too many files have changed in this diff Show More