Files
X-Financial/document/development/小财管家/CONCEPT.md
caoxiaozhu f60cebadb8 feat: 小财管家意图规划与报销提交编排增强
- 完善管家意图识别、模型计划构建与规划器调度
- 重构差旅报销提交编排器与管家计划流程前端交互
- 优化报销消息项样式与文档中心视图
- 新增小财管家与附件上传风险前置复核设计文档
- 补充管家规划器与文档中心测试覆盖
2026-06-04 14:25:14 +08:00

391 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 小财管家
## 功能一句话
小财管家是首页统一财务任务入口,负责把用户的自然语言和附件拆解为多个可确认、可追踪、可分派的申请与报销任务,再调用现有申请助手和报销助手完成执行闭环。
## 背景与问题
当前个人工作台已经提供首页输入框,并能通过本体解析把一句话路由到申请、报销、预算或知识等单一会话。这个能力适合单意图,但用户真实表达经常是多任务组合,例如同时包含出差申请、昨日交通费报销、历史出差费用报销以及多张附件。
现有问题:
- 首页输入框当前会收敛为一个 `sessionType`,无法保留多任务计划。
- 申请助手和报销助手已经具备单任务核对能力,但缺少上层任务拆解、归集和跨助手分派。
- 附件上传后主要进入当前会话,缺少面向多任务的自动归集建议。
- 财务动作需要确认后才能入库、绑定或提交,不能让大模型直接执行高风险动作。
- 新增字段必须尊重本体字段,不能因为小财管家新增一套业务字段。
## 目标与非目标
### 目标
- 首页输入框定位为“小财管家”,作为用户默认财务任务入口。
- 用户提交自然语言和附件后,先展示小财管家的任务识别与附件归集过程。
- 支持把一句话拆成多个任务,第一版只验证费用申请和费用报销。
- 支持多附件按费用场景、时间、地点、任务线索形成归集建议。
- 遇到创建申请单、创建报销草稿、附件绑定、提交审批等动作时必须等待用户确认。
- 保留现有申请助手和报销助手能力,小财管家只做上层编排和分派。
- 外层意图识别必须优先使用大模型 function calling 输出结构化任务计划,规则逻辑只作为模型不可用或结构不合法时的兜底。
- 前端展示“意图识别智能体”过程气泡,并用流式状态逐步呈现,不暴露模型内部推理链。
- 所有业务字段先进入本体字段归一化,再进入下游助手、草稿、风险规则和持久化。
### 非目标
- 第一版不做万能智能体,不覆盖预算、审批、知识问答等全部场景。
- 第一版不引入 LangChain 或 LangGraph先复用项目内运行时模型配置和 OpenAI-compatible function calling 契约。
- 第一版不自动提交审批,不绕过用户确认。
- 第一版不新增业务语义字段;只新增任务编排态字段。
- 第一版不重写申请助手、报销助手和现有 Orchestrator。
## 用户与场景
### 目标用户
- 普通员工:在首页一次性描述申请、报销和附件处理诉求。
- 财务人员:查看任务拆解、附件归集和用户确认链路是否可追溯。
- 审批/管理角色:后续可扩展为审批待办和预算提醒编排,但不进入第一版。
### 核心场景
用户在首页输入:
```text
我想要申请7月2日去北京出差辅助北京供电局的税务审核任务并且我要报销昨天的交通费还需要报销6月3日出差去上海的费用
```
系统处理:
1. 小财管家识别到三条候选任务。
2. 将“昨天”按客户端日期解析为明确日期,例如 2026-06-03。
3. 将“7月2日去北京出差”归为费用申请任务。
4. 将“昨天的交通费”和“6月3日去上海出差费用”归为费用报销任务。
5. 如果用户同时上传附件,系统先识别附件场景,再建议归集到对应任务。
6. 需要创建申请单或报销草稿时,向用户展示核对摘要和确认动作。
## 功能能力
### 1. 任务识别与拆分
任务识别主链路是“小财管家意图识别智能体”:
1. 后端读取系统设置中的主模型/备模型运行时配置。
2. 将用户话术、客户端日期、附件元信息、上下文和 canonical ontology field 列表传入模型。
3. 通过强制 function calling 调用 `submit_steward_intent_plan`
4. 模型只能返回结构化参数:`thinking_events``tasks``attachment_groups`
5. 服务端再次校验:任务类型只能是 `expense_application` / `reimbursement`,业务字段只能是 canonical ontology fields附件名必须来自本次上传。
6. 如果模型未配置、调用失败、未返回工具调用或结构不合法,才切换到规则兜底,并在过程摘要中标记兜底原因。
输入:
- 用户自然语言 `message`
- 附件元信息 `attachments`
- 当前用户、部门、角色、客户端时间
- 已有会话上下文,可选
输出:
- `plan_id`:本次小财管家计划 ID
- `tasks`:多个任务条目
- `thinking_events`:面向用户展示的过程摘要
- `confirmation_groups`:需要用户确认的动作集合
- `attachment_groups`:附件归集建议
任务条目包含:
- `task_id`:编排态任务 ID
- `task_type``expense_application``reimbursement`
- `assigned_agent``application_assistant``reimbursement_assistant`
- `title`:任务标题
- `summary`:任务摘要
- `status``planned``needs_confirmation``ready_to_delegate``delegated``completed``blocked`
- `confidence`:识别置信度
- `ontology_fields`:归一化后的本体字段
- `missing_fields`:缺失字段
- `confirmation_required`:是否需要确认后执行
### 2. 附件归集
附件归集基于以下信号:
- 附件类型:发票、火车票、机票、酒店票、付款截图、招待票据等。
- 费用场景:差旅、交通、招待、住宿、其他。
- 日期:票据日期是否匹配任务时间。
- 地点:票据地点是否匹配任务地点。
- 金额:是否能参与报销草稿。
- 置信度:低置信度必须提示用户核对。
输出示例:
```json
{
"group_id": "ag_travel_001",
"target_task_id": "task_reim_002",
"scene": "travel",
"scene_label": "差旅费用",
"attachment_names": ["上海高铁票.jpg", "上海酒店发票.pdf", "出租车票.png"],
"excluded_attachment_names": ["客户招待发票.jpg"],
"confidence": 0.86,
"confirmation_required": true
}
```
### 3. 用户确认
必须确认的动作:
- 创建费用申请单。
- 创建报销草稿。
- 将附件归集并绑定到某一任务。
- 将附件关联到已有报销草稿。
- 提交审批。
- 修改已有草稿字段。
小财管家的确认动作采用“下一步优先”策略:
- 同一个计划里同时存在申请和报销时,前端只展示当前下一步主动作,不一次性摊开全部确认按钮。
- 下一步优先级为:费用申请单创建 > 报销单填写 > 附件归集确认。
- 小财管家先思考和分析,说明下一步将要做的行为;用户输入“确定”或点击确认后,才进入行动。
- 行动完成后重新检查剩余任务队列,继续进入“思考 -> 分析 -> 等待确认 -> 行动”的循环。
- 申请任务完成后,再把剩余报销任务作为后续任务引导到报销助手。
- 附件归集不作为第一屏主动作抢占申请流程;当进入报销任务时,相关附件随报销上下文带入。
可以自动执行的动作:
- 任务拆解。
- 本体字段归一化。
- 附件分类。
- 缺失字段检查。
- 风险和规则预审。
- 生成确认摘要。
### 4. 流式过程摘要
前端展示的是“意图识别智能体”的过程摘要,不是模型内部推理链;过程摘要必须独立于最终回复正文展示。
示例:
```text
正在识别用户输入中的财务事项...
已识别到 3 个候选任务。
正在按时间、地点和费用场景核对附件...
发现 3 张附件疑似属于差旅费用1 张附件需要单独处理。
等待你确认后,我再创建申请单或报销草稿。
```
第一版通过 `POST /steward/plans/stream` 返回 `application/x-ndjson` 流式事件:
- `thinking`:逐条追加到系统回复气泡上方的独立“意图识别智能体”折叠气泡。
- `plan`:返回完整任务计划后,再渲染最终正文、任务卡片、附件归集和确认动作。
流式接口必须在模型 function calling 完成前先返回首个 `thinking` 事件,告知用户“意图识别智能体接管”。后续模型返回后再追加结构化拆解、字段映射、附件归集等过程摘要。
前端收到 `thinking` 事件后,也必须以 typewriter 方式逐字展示过程摘要,不能把一条完整思考事件一次性塞进折叠气泡。多条 `thinking` 事件应排队顺序输出,上一条内容打完后再输出下一条。
前端流式超时必须区分“首包等待”和“流式空闲等待”:首包应快速返回,收到首包后不能再用固定总时长中断仍在思考的模型调用,只能在长时间没有任何新事件时判定空闲超时。
流式过程中正文区域不输出任务结论;计划完成后意图识别气泡默认折叠,正文只保留用户需要确认和执行的信息。
计划完成后的最终正文也必须流式输出。前端不能把完整正文一次性替换到消息气泡里,而应进入 `typing` 状态按字符逐步追加正文;正文输出完成后,再把状态改为“等待用户确认”并展示确认按钮。
用户确认当前步骤后,小财管家隐式委派给申请能力或报销能力时,也必须保持同一套流式体验:先在系统气泡上方的小财管家思考折叠气泡中逐字展示“接收确认、协调能力、等待结果”等过程摘要;拿到申请核对表或报销核对结果后,再逐字输出正文。结构化表格、核对卡片、确认按钮可以在正文输出完成后一次性展示,但正文不能一次性替换进消息气泡。
小财管家委派期间不得打开右侧单助手执行流程面板,也不得把“申请助手 / 报销助手”的执行步骤显示成独立助手思考框。用户可见身份保持“小财管家”,具体调用哪个能力只作为小财管家自己的过程摘要,不切换为“财务助手”或单独助手会话。
### 5. 用户可见结果展示
小财管家的第一屏最终正文必须采用适中信息量的分段结构:让用户看懂系统理解了哪些财务事项、先后顺序是什么、每一步会交给哪个助手做什么;但不要把任务摘要、置信度、字段缺口和附件判断提前摊开。
第一屏推荐结构:
1. `我会这样推进`:说明识别到几个财务事项,以及会逐步处理。
2. 顺序列表:说明先做什么、后做什么,每步附一句负责助手和动作边界。
3. 确认提示:请用户回复“确定”后开始第一步,并说明具体缺口会在对应步骤里再判断。
最终正文必须使用 Markdown 块结构渲染,至少包含标题、段落和顺序列表;标题与段落之间必须保留空行,并通过 `steward-plan-markdown` 专属样式拉开块间距。不能只依赖普通换行拼接文本,因为普通换行在对话气泡里会显得拥挤。
第一屏不展示任务详情卡片里的“还需要补充”,也不展示字段缺口说明。用户确认开始后,进入当前步骤的申请助手或报销助手,再由具体助手基于当前任务判断需要补充什么。
后续步骤如果需要展示“还需要补充”,必须是结构化列表,每个待补充项独立成行,包含字段业务名称和填写说明;不得把多个待补充项拼接成一行连续文本。
任务卡片和正文不得直接暴露本体字段名,例如 `transport_mode``amount``attachments`。本体字段只允许作为内部结构化数据进入后端、助手委派和持久化链路;用户界面必须翻译为业务中文,并提供可理解的填写说明:
- `transport_mode` 展示为“出行方式”,说明可填写高铁、飞机、自驾、出租车等。
- `amount` 在申请任务中展示为“预计金额”,在报销任务中展示为“报销金额”。
- `attachments` 展示为“附件/凭证”,说明可上传发票、行程单、付款截图或其他证明材料。
- `merchant_name` 展示为“商户/开票方”。
- `customer_name` 展示为“客户或项目对象”。
## 本体字段约束
业务字段必须使用本体 canonical field
- `expense_type`
- `time_range`
- `location`
- `reason`
- `amount`
- `transport_mode`
- `attachments`
- `customer_name`
- `merchant_name`
- `department_name`
- `employee_name`
- `employee_no`
兼容字段只能作为输入别名,例如:
- `occurred_date` -> `time_range`
- `business_time` -> `time_range`
- `reason_value` -> `reason`
- `transport_type` -> `transport_mode`
- `application_transport_mode` -> `transport_mode`
小财管家的编排态字段不进入业务语义本体:
- `plan_id`
- `task_id`
- `planning_source`
- `model_call_traces`
- `task_status`
- `assigned_agent`
- `confirmation_status`
- `attachment_group_id`
- `thinking_event_id`
这些字段只用于编排、展示和审计,不参与费用规则判断。
## 方案设计
### 后端
新增小财管家规划服务:
- `schemas/steward.py`:定义请求、任务计划、附件归集、确认动作等契约。
- `services/runtime_chat.py`:新增 `complete_with_tool_call`,复用主/备模型配置发送 `tools``tool_choice`
- `services/steward_intent_agent.py`:负责构造 `submit_steward_intent_plan` function schema 与模型调用。
- `services/steward_model_plan_builder.py`:负责把模型工具参数转换为服务端可校验计划。
- `services/steward_planner.py`:负责“大模型 function calling 优先、规则兜底”的编排和本体字段归一化。
- `api/v1/endpoints/steward.py`:提供 `POST /steward/plans``POST /steward/plans/stream`
后端第一版不直接落库业务单据,只返回计划和确认动作。确认后的执行仍走现有申请助手、报销助手和 Orchestrator。
### 前端
新增或改造能力:
- 首页输入框标题和提示文案改为“小财管家”。
- 工作台打开时默认使用 `sessionType=steward`
- 小财管家模式下隐藏“智能体切换”工具条。
- 小财管家模式下不展示欢迎界面。
- 小财管家模式下使用专属底部输入框,仅保留附件、自然语言输入和发送动作。
- 小财管家模式下先流式渲染独立过程摘要,再渲染任务计划正文。
- 用户确认当前下一步后,再切换/分派到申请助手或报销助手执行;多任务按顺序推进,不把所有任务动作一次性展示给用户。
### 执行流
```text
首页输入
小财管家计划接口
意图识别智能体 function calling
思考过程流式输出 + 任务分析 + 下一步动作说明
等待用户输入“确定”或点击确认
小财管家隐式调用申请助手创建申请单核对结果
申请动作完成后重新思考剩余队列
继续等待确认并隐式调用报销助手填写报销单
执行结果汇总
```
## 算法与公式
第一版主路径不以关键词规则定义“意图”,而是使用大模型 function calling 生成结构化计划。
模型输出后由服务端做确定性校验、字段归一化和确认动作生成。
规则置信度评分仅用于模型不可用或模型返回结构不可用时的兜底路径。
任务置信度:
$$
confidence = \min(1, 0.35s_i + 0.25s_t + 0.2s_l + 0.2s_a)
$$
变量说明:
- `s_i`:意图关键词得分,命中申请/报销核心动词。
- `s_t`:时间得分,识别到明确日期、相对日期或时间范围。
- `s_l`:地点得分,识别到城市、客户或业务对象。
- `s_a`:附件/费用场景得分,识别到票据、交通、住宿、招待等费用线索。
附件归集置信度:
$$
group\_score = 0.4m_s + 0.3m_t + 0.2m_l + 0.1m_n
$$
变量说明:
- `m_s`:附件场景与任务场景匹配度。
- `m_t`:附件日期与任务日期匹配度。
- `m_l`:附件地点与任务地点匹配度。
- `m_n`:附件名称和任务关键词匹配度。
## 测试方案
### 后端单元测试
- function calling 路径能把模型工具参数转换为 `planning_source=llm_function_call` 的任务计划。
- 模型返回 `occurred_date``transport_type``reason_value` 等别名时,服务端仍只输出 canonical 字段。
- 一句话中同时包含申请和报销时,返回多个任务。
- “昨天”能根据 `client_now_iso` 解析为明确日期。
- `occurred_date``transport_type``reason_value` 等兼容字段不会作为业务 canonical 字段输出。
- 多附件能生成差旅归集建议和排除项。
- 创建/绑定/提交类动作必须带 `confirmation_required=true`
### 前端测试
- 首页输入复杂话术后打开小财管家模式。
- 小财管家模式标题显示“小财管家”,不展示智能体切换。
- 过程摘要按步骤渐进展示。
- 任务计划卡片展示申请任务和报销任务。
- 附件归集建议展示包含项、排除项和确认按钮。
### 容器验证
后端测试必须在 `x-financial-main` 容器内执行:
```bash
docker exec -w /app -e SERVER_VENV_DIR=/tmp/x-financial-server-venv x-financial-main /tmp/x-financial-server-venv/bin/pytest -q server/tests/test_steward_planner.py
```
前端构建优先使用宿主机 `npm.cmd` 或项目既有脚本,并设置合理超时。
## 指标与验收
- 输入包含 3 个任务的示例话术时,至少识别出 1 个申请任务和 2 个报销任务。
- 输入“明天出差北京3天支撑国网仿生产部署并且报销昨天业务招待费”时必须识别出 1 个申请任务和 1 个报销任务。
- 模型可用时,小财管家计划响应包含 `planning_source=llm_function_call`
- 小财管家计划响应中业务字段只出现 canonical ontology fields。
- 附件场景混合时,能区分差旅相关附件和非差旅附件。
- 前端弹窗标题为“小财管家”,并隐藏智能体切换。
- 前端确认区只展示当前下一步主动作;存在申请任务时,第一步必须是“先创建申请单”。
- 意图识别折叠气泡不得宽于正文气泡,且流式首包必须先于最终计划到达。
- 用户未确认前,不创建申请单、不创建报销草稿、不绑定附件、不提交审批。
- 后端定向测试通过。
## 风险与开放问题
- 模型供应商对 tools/function calling 的兼容度可能不同;第一版保留规则兜底和主备模型 failover。
- 规则兜底无法覆盖所有自然语言,需要保留人工确认和低置信度提示。
- 附件真实 OCR 归集依赖现有票据识别质量;第一版先使用附件名称和已有 OCR 摘要做轻量归集。
- NDJSON 流式输出展示的是过程摘要,不是模型内部推理链。
- 多任务之间可能共享日期、地点、申请单上下文,需要后续完善任务图依赖。
- 如果未来接入 LangGraph应基于当前计划契约迁移而不是推翻现有申请/报销助手。