ticket/README.md

78 lines
5.9 KiB
Markdown
Raw Permalink 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.

# ticket — 平台工单管理模块
客户提出问题 → 登记工单 → agent 先处理(检索'0'机构知识库+历史工单,能答直接回复客户)
→ 答不了转人工运维owner.maintainerparams 可配)→ 人工回复客户 → 关闭;
人工处理不了可转派 owner 组织类型下任意角色或具体用户。
## 关键设计(详见 pipeline-app/docs 或设计文档 ticket-module-design.md
- **状态机**8 态 13 迁移全部乐观锁UPDATE...WHERE status=前置态 + SELECT 验证,
照 pipeline_service agent_loop 的 claim 范式),并发冲突返回明确错误码。
- **平台待办集成**(用户定夺 2026-09-10工单不建独立通知表通过
`register_todo_provider` 钩子接入平台待办通道pipeline-service 聚合,
todo_badge 角标 + my_todos 弹窗异步通知到人)。待办由工单状态派生:
客户回复待确认 / 运维角色池待认领 / 受理人待处理——状态流转待办自动消失,
天然满足「同一事项只发一次」。
- **角色不硬编码**:默认受理角色存 paramsticket_default_role兜底 owner.maintainer
转派候选实时查 role 表 owner 组织类型全部角色 + '0' 机构用户role/orgtypes 运行时可动态增删)。
- **agent**:异步 poller照 bid_flow 范式PIPELINE_MODE=web 不启动),
RAG 检索走 rag HTTP APIdapi Bearer key平台账号='0'机构 → 只见 org_id='0' 的 KB
LLM 走 pipeline_service.llm_bridge.llm_call内部 token+门禁链+记账org_id='0')。
「能否回答」由 LLM 裁决(语义判断铁律,禁关键词匹配),严格 JSON 输出;
硬门禁reply 空/短于20字符一律转人工。基础设施故障LLM/RAG异常≠答不了
fail_rounds+1 回退重试≥3 轮转人工reason=agent服务不可用
## 数据表3张tk_ 前缀)
| 表 | 说明 |
|---|------|
| tk_tickets | 工单主表(状态机+当前受理角色/人+agent处理锁customer_user_id 必填=提单人,待办精确到人) |
| tk_messages | 往来消息visibility: customer客户可见/internal内部备注attachments JSON 列存附件清单) |
| tk_transfers | 转派流水append-only每次受理方变更必留痕 |
## 附件2026-09-11 上线,全链路)
- **上传**客户建单表单Form uitype=file multiple、追问/回复弹窗UiFile multiple
FormData multipart → ahserver getPostData 自动落 FileStoragefilesroot按用户目录分片
params_kw['attachments'] 得 webpath单 str / 多 list。前端拦截单条 ≤9 个、总量 ≤9.5MB。
- **服务端规整**core.normalize_attachments 生成 [{id,name,webpath,size}](不信任客户端):
路径必须 '/' 开头无 '..'、realpath 不越出 filesroot、真实存在并调 tfr.file_useful 把文件
从临时清理队列摘除(否则 multipart 上传 1 小时后被当临时文件删)。错误码 TK_E014。
- **展示**ticket_detail_popup.dspy页面详情与平台待办共用消息流内联附件行 +
末尾「全部附件」汇总区;上传方彩色徽标区分(客户蓝/智能助手紫/人工客服橙)+昵称。
附件不做 markdown 链接——MdWidget 会劫持同源 <a> 为加载 markdown用独立按钮行。
- **打开/下载**ticket_attachment.dspymsg_id+att_id 反查I5 服务端校验:客户只能取
visibility=customer 消息附件staff/admin 全量)→ FileResponse?download=1 加 attachment 头。
文本类显式 Content-Type charset=utf-8aiohttp FileResponse 猜类型不附 charset → 中文乱码)。
错误码 TK_E015附件不存在/丢失。load_path 已注册 logined。
## 参数params 表,运行时可改)
| 参数 | 默认 | 说明 |
|------|------|------|
| ticket_default_role | owner.maintainer | agent 转人工的默认受理角色 |
| ticket_followup_max | 2 | agent 回复后客户追问上限,超限自动转人工 |
| ticket_agent_fail_max | 3 | agent 基础设施连续失败轮数上限,超限转人工 |
| ticket_agent_username | admin | agent 检索知识库用的平台账号('0'机构) |
| ticket_platform_kb_name | 平台知识库 | 人工工单沉淀的目标知识库名('0'机构,不存在时自动创建 bge-m3 文本库) |
## 人工工单自动沉淀知识库2026-09-12 上线kb_ingest.py
人工处理过的工单关闭后自动归档进「平台知识库」,下次同类问题 agent 检索即可自动回答,形成闭环。
- 触发:`core.ticket_confirm`客户确认解决→closed/resolved成功后 `schedule_ingest(ticket_id)` 派发后台任务。
- 入库条件:工单 close_reason=resolved **且**存在人工对客回复sender_type=staff, visibility=customer纯 agent 自答的不沉淀。
- 正文:客户问题 + 处理过程(仅客户可见消息)+ 结论(最后一条客服答复)。**internal 内部备注一律排除**,防内部排查信息经 agent 回复泄露给客户。
- 幂等:同 KB 同名文档(工单<ticket_no>-<标题>.md已存在则跳过。
- 通道:只走 rag 对外 APIkb_list/kb_create/doc_upload不直写 rag 表;仅 SQL 读 rag_documents 查重。身份与 agent.py 同款params ticket_agent_username 的 '0' 机构账号,经 pipeline_service.rag_client 取 Bearer key
- 软降级pipeline_service/rag 不可用、API 异常、上传失败只记日志,绝不影响工单关闭动作。
E2E 实测(测试机 2026-09-12人工工单关闭→自动生成 .md 入库status=done, 8 chunks`_platform_rag_search` 检索该问题命中 score=1.0/0.97/0.71internal 备注未泄漏;测试工件已清理。
## 安装
宿主 build.sh 四处清单 + `load_ticket()`(见宿主集成)。模块注册:
- env.create_ticket / ticket_detail / ticket_followup / ... dspy 消费)
- register_todo_provider(list_ticket_todos)(平台待办聚合)
- start_poller()agent 后台处理)