企享云自然语言开票 Skill
本 Skill 用于自然语言开票闭环:接收用户开票需求后,先通过一次性外部网页获取销方企业和办税账号,再解析需求、用云抬头补齐购方,结合商品和金额字段生成草稿与确认摘要;只有用户明确确认后才调用真实开票 MCP。一次性登录同样通过企享云 MCP 服务完成,Skill 不直连登录后端。
用户可见输出
脚本 stdout、结构化错误、login_url、agent_handoff 和业务诊断字段都属于 Agent 私有
编排资料,不得整包复制给用户。面向用户时只输出简短自然语言、必要的业务确认和
user_interaction.message:
- 登录入口只渲染为
[打开登录页面](<实际一次性地址>),不得显示裸 URL;不要接入
第三方短链服务,以免额外泄露一次性地址。 - 需要访问凭证时只说“请把开放平台复制出的完整访问凭证直接发给我”,不得说明环境
变量名、分隔格式、配置文件、stdin/argv、脚本路径或内部检查命令。 - 业务文件链接统一使用
[下载 PDF 发票](<实际地址>)、[下载 OFD 发票](<实际地址>)
等有意义的文字;结果含非空user_download_message时必须原样逐行渲染。禁止只说
“链接已附上”却不实际输出链接;字段为空时也不得声称已有链接。 - 只展示用户做决定所需的购销方名称、发票类型、商品、金额、税额、状态和下一步。
flow、Grant、内部 ID、工具名、请求参数、原始响应、摘要、路径及调试信息一律不展示。
产品授权终态
业务或登录 MCP 返回 code=505069 且命中已登记的测试期/测试次数文案时,只向用户回复:
“您当前使用的是免费版,该产品的测试使用期已结束。为了不影响您的业务正常开展,建议您前往企享云开放平台选购付费版或进行续费,感谢您的支持!”
命中生产次数/税号数量文案时,只回复:
“抱歉,您的产品生产授权已到期,当前服务已暂停。为确保您的业务持续稳定运行,请尽快前往企享云开放平台完成续费或购买,感谢您的配合!”
这是不可重试的失败终态:立即停止当前流程,不重新登录、不索取或重配 APIKEY、不自动重试,也不追加购方、金额、额度或参数修正建议。不得展示原始响应或原始服务端文案。
前置条件:凭证配置
本 Skill 依赖企享云开放平台访问凭证。用户尚未申请时,只提供
申请访问凭证;不得把下面的
Agent 私有配置协议转述给用户。
凭证检查与配置:
- 按“进程环境 → 当前 Skill
.env→qixiangyun-skill/.env”的优先级读取
QXY_API_KEY。本地单用户 Agent 首次使用必须显式运行
python3 scripts/mcp_client.py --check-config --allow-agent-credential-configuration;普通
--check-config只做检查,不开放对话凭证配置。 - 值必须是开放平台复制出的完整原值。同一配置来源不得同时保留
QXY_CLIENT_APPKEY/QXY_CLIENT_SECRET等旧拆分变量,也不得由 Agent 猜测或拼接旧值。 - 本地单用户模式下,如果检查结果返回
configuration_required=true和
credential_delivery=user_to_agent_plaintext,用户可以把完整 APIKEY 发送给当前 Agent;
Agent 必须先说明该消息仍受当前对话平台的留存策略约束。用户不需要手工编辑.env,
已经提供完整访问凭证时也不应再被要求重复配置或回复“重试”。用户直接粘贴开放平台
复制出的完整原值;配置器兼容用户误带的一层配置项前缀,但重复前缀必须拒绝。 - Agent 收到完整 APIKEY 后不得复述、展示或记录其值。必须原样使用检查结果中的
agent_configuration.argv参数数组;当前固定契约为
configure_credentials.py --agent-stdin --local-single-user。启动子进程时设置
shell=False,并把{ "QXY_API_KEY": "用户原始输入" }作为单字段 JSON 直接写入
子进程 stdin;禁止把凭证放进 argv、shell 命令或管道、进程列表、stdout、stderr、
日志、临时交接文件或工具输出。 - 配置脚本以原子替换方式更新当前 Skill 的
.env,POSIX 下权限为0600,清理其中的
QXY_CLIENT_APPKEY/QXY_CLIENT_SECRET旧拆分变量且只保留一个QXY_API_KEY。它不会用
旧值拼装新凭证。成功后 Agent 自动执行普通--check-config复检并继续原业务,不把恢复
操作转交给用户。向用户发送的user_interaction.message不得包含本节字段名、格式或
命令。stdin 只降低凭证进入 argv、shell、进程列表和输出的风险,不能消除
用户消息已进入当前对话平台这一事实。 - 集中托管、多租户、企业共享、只读或没有每租户私有持久盘的平台不得使用上述本地
对话落盘流程,也不得传--allow-agent-credential-configuration;必须由平台 Secret
或密钥管理系统按租户注入,并隔离容器、系统账号、私有目录、worker 与日志。多个用户
禁止共用同一个 Skill.env。公共共享.env中的旧版或畸形凭证属于部署错误,不能
用当前 Skill.env遮蔽。
详细安全边界和只读/云托管环境处理见
references/credential-setup.md。
一次性网页登录强关联
所有发票相关能力(开票、已开发票查询、人脸认证、红票、特殊蓝票)都必须先通过 scripts/invoice_issuance_workflow.py 创建或恢复企业配置。仅首次没有已 ACK 本地企业配置时创建一次性网页登录;初次网页登录不得要求用户在对话中提供税局手机号、密码、验证码或登录 Token,也不得使用工商查询、租户列表或模型记忆替代网页最终返回的 nsrsbh/accountId/aggOrgId。后续税局会话刷新按下述聊天验证码流程接收一次短期短信验证码,不再打开网页。
普通用户和外部 Agent 不需要配置任何 QXY_AGENT_LOGIN_* 地址或密钥。脚本使用内置的企享云 agent_login MCP 服务,并复用前述 QXY_API_KEY 做产品准入。即使多个用户共用同一 appkey,也不能凭 appkey 或 request_id 读取彼此结果:Skill 会为每次登录自动生成独立的 256 位随机证明,只把 S256 challenge 发给创建接口,原始证明仅保存在本机 0600 私有流程文件中,查询和 ACK 都必须同时持有该证明。
登录完成后,顶层企业是实际完成登录的主企业,enterprises[] 是同一短期
agentGrant 授权的全部成功企业,failedEnterprises[] 仅记录准备失败项。Skill 在 ACK
前把 Grant、过期时间、完整授权列表、主企业、活动企业和失败列表一次原子写入对应
0600 flow 文件。已 ACK 的 authenticatedEnterprises[] 是本地企业配置,生命周期不随
短期 Grant 结束;失败企业绝不进入授权集合。Grant 有效时才附加
X-QXY-Agent-Grant,过期或被服务端在执行工具前拒绝时保留企业配置,改由本地 APIKEY
与同一企业的精确绑定继续。详细字段见
references/agent-login-api.md。
登录链接默认有效 1 小时;网页完成后签发的 Agent Grant 默认有效 24 小时。Skill 在调用
企享云 agent_login MCP 创建工具时携带私有 grant_context,MCP 只在服务端消费该对象,
不得把它转发给 client-server 的登录创建接口。链接过期时重新运行原命令生成新链接。
税局自身会话可能早于 Grant 失效,不能承诺税局会话保持 24 小时。切换到
enterprises[] 内已授权企业时,Agent 使用同一私有
--login-context-id 调用内部 list-enterprises / select-enterprise,只原子更新活动企业,
不得创建、轮询或 ACK 新会话,也不得由选择命令发送验证码、替换或撤销 Grant。名称不唯一或同税号
存在 KPY/BSY 多身份时必须用 sflx 消歧,不能猜测。目标不在列表、Grant 失效或状态损坏
都不得自动创建第二个页面;只有用户明确说“配置企业”“重新配置企业”或“增加企业”后,
才可把 --switch-account 作为替换整份企业配置的兼容入口,例如:
python3 scripts/invoice_issuance_workflow.py login \
--login-context-id Agent内部会话ID \
--switch-account
授权内选择完成后,或业务 MCP 明确提示税局会话失效时,Agent 调用
scripts/managed_login_flow.py ensure。缓存或快速登录有效则直接继续;需要短信时只提示用户
在聊天框输入验证码,再用 submit --sms-code-stdin 敏感 stdin 提交,不询问手机号、密码、
taskId 或内部企业 ID,也不回显、记录或持久化验证码。发送和提交均不自动重放;结果不确定
时停止并先检查登录状态。Grant 失效不触发网页,仍以首次保存的活动企业进入聊天验证码
流程。完整流程见
references/chat-managed-login.md。
所有需要税局身份的后续 MCP 调用都必须绑定当前已 ACK flow 的企业集合;每组业务字段
必须准确命中其中同一项。有效 Grant 只作为附加短期 Header,过期或无效时不得再发送,
而由本地 APIKEY 和已保存企业绑定继续;不得扩大到列表外企业。共享 APIKEY 必须留在
平台代理端,并隔离每租户的容器、私有目录、
worker 和事件通道。具体边界见 references/credential-setup.md。
如果登录 MCP 暂不可用,只能提示“登录服务暂不可用,请稍后重试或联系服务方”;不得要求普通用户配置 QXY_AGENT_LOGIN_SECRET、API 地址、域名白名单,也不得切换到离线登录或收集税局账号密码。
面向用户的 login_url 必须是用户设备可访问的 HTTPS 地址,不能是 127.0.0.1 或仅 Agent 所在机器可达的内网 IP。正式域名白名单随 Skill 发布;QXY_AGENT_LOGIN_MCP_ENDPOINT、QXY_INVOICE_INQUIRY_MCP_ENDPOINT、QXY_AGENT_LOGIN_ALLOWED_PUBLIC_HOSTS 与 QXY_AGENT_LOGIN_ALLOW_HTTP 只允许开发、测试或私有化部署人员覆盖,不能作为普通用户的使用步骤。本机联调发票查询时,登录与 invoice_inquiry 端点必须指向同一可信 MCP 部署。开发人员可将覆盖项写入 Skill 根目录或 qixiangyun-skill 公共父目录的 .env;系统环境变量优先,其次是 Skill .env、公共 .env,未设置时继续使用内置生产地址。
所有运行态默认保存在 Skill 包外的私有根目录
~/.qixiangyun/invoice-issuance;部署方可通过 QXY_INVOICE_ISSUANCE_STATE_DIR
覆盖为租户隔离、权限受限、可写且需要时可持久化的目录。Skill 包目录只包含可分发源码,
不得保存 flow、开票状态、草稿或企业账号数据。POSIX 下运行态根目录及子目录必须为
0700,文件必须为 0600;Windows 使用等价的每用户 NTFS ACL。
发布时不得递归打包开发工作目录;必须按受控源码清单构建,并在产物中阻断
.agent_login_flows、.invoice_flow_state*、.generated、.env 等历史运行态或凭证文件。
平台无关交接协议
python3 scripts/invoice_issuance_workflow.py login \
--login-context-id Agent内部会话ID
--login-context-id 在本地单用户模式可选,在同一 Agent 进程/系统账号服务多个用户的云端模式必须传入稳定且不可猜测的内部租户+会话标识。它只在本机生成 SHA-256 指纹,原始 OpenClaw/session/thread/user 标识既不落盘也不发送给登录服务。草稿会保存 loginContextHash,后续 resume-flow/issue/query-result/face-* 必须由 Agent 携带同一个 --login-context-id;用户不保存、不查看也不输入该值。脚本返回两层字段:
- 面向用户:只渲染
user_interaction.message - 仅供 Agent:原始
login_url、flow_id和agent_handoff.waitArgv/waitCommand
Agent 必须:
- 原样渲染
user_interaction.message中的文字链接,不单独发送login_url;不得展示
flow_id、waitCommand、原始 JSON 或服务端request_id。 - 立即在 Agent 内部以后台任务启动
agent_handoff.waitArgv;支持 argv 的平台必须直接传数组并禁用 shell。 - 只有后台任务确认启动成功后,才能告诉用户“完成后无需回复,我会自动通知”;启动失败时返回平台任务错误,不得要求用户改为保存 ID。
- 后台任务输出
qxy.agent_login.completed后,把顶层字段视为主企业,把
enterprises[]视为同一 Grant 的授权集合,把activeEnterprise视为新业务默认企业。
用户已说明目标企业时,按企业名称匹配;名称/税号不唯一时询问 KPY/BSY 身份后再执行
内部select-enterprise,最终必须落到同一项的aggOrgId+accountId,不得跨企业拼接。
resumeContextRequired=true时在参数数组末尾附加原--login-context-id。
直接运行 login 时这些字段位于顶层;通过 draft 或 query-invoices 触发时位于 login 节点。服务端 request_id、原始会话证明和短期 Agent Grant 只保存在包外私有运行态根目录中权限为 0600 的 flow 文件里,不进入用户回复、Agent 事件或命令参数,Agent 与用户都不需要操作它们。
后台等待命令的通用形式:
python3 scripts/invoice_issuance_workflow.py wait-login \
--login-flow-id Agent内部flow_id \
--timeout-seconds 3660
--timeout-seconds 0 表示只检查一次,适用于不能运行后台进程、但有任务队列或调度器的自研 Agent。
长等待会按服务端建议间隔轮询,最低约 5 秒;持续等待约 30 秒后自动退避到约 10 秒并加入轻量向后随机抖动,避免多个 Agent 同时轮询造成请求和日志洪峰。服务端建议间隔大于 10 秒时优先遵循服务端值。
完成事件示例:
{
"event": "qxy.agent_login.completed",
"success": true,
"flow_id": "Agent内部流程句柄",
"nsrmc": "企业名称",
"nsrsbh": "纳税人识别号",
"orgId": "企业ID",
"accountId": "办税账号ID",
"next_action": "resume_original_operation",
"resumeContextRequired": true,
"resumeArgv": ["python", ".../invoice_issuance_workflow.py", "resume-flow", "--login-flow-id", "Agent内部流程句柄"]
}
原始业务参数已保存在本机 0600 私有状态中;Agent 可直接执行完成事件中的 resumeArgv。进程重启后原需求仍可恢复,但平台必须重新启动 wait-login 或由持久化 worker/调度器继续检查,不能假设内存中的后台任务跨重启存活:
python3 scripts/invoice_issuance_workflow.py resume-flow \
--login-flow-id Agent内部flow_id \
--login-context-id Agent内部会话ID
Agent 平台适配
- OpenClaw:用
exec将agent_handoff.waitCommand作为后台任务启动,并设置超时大于agent_handoff.timeoutSeconds。确认后台任务已启动后再发送登录链接;命令退出后由 exec 完成通知唤醒原会话,并按resumeContextRequired规则续跑。OpenClaw Gateway 重启会丢失内存中的后台 session,要求跨重启自动恢复时必须另配持久化 worker/调度器。不要把 OpenClaw Gateway 暴露公网来接收回调。 - 自研 Agent:把
waitArgv交给自己的 worker/任务队列并禁用 shell,保存 job 与原始内部 context 的关联,按 stdout JSON 事件恢复原 job/thread,再按resumeContextRequired规则执行;如果只能短请求,定时执行wait-login --timeout-seconds 0。 - 集中托管 Agent:可以在平台边界内把完成事件转入内部消息队列,但核心 Skill 不接受任意
callbackUrl,避免 SSRF、跨租户投递和密钥泄漏。即使租户共用同一 appkey,也必须按租户隔离系统账号/容器、QXY_INVOICE_ISSUANCE_STATE_DIR、worker 队列和事件通道;会话证明只存在于对应租户的私有状态中。
网页不会直接回调本机 Agent。wait-login 只建立 Agent 到企享云 MCP 的出站连接,因此适配 OpenClaw、本地 Agent、容器和 NAT 网络。脚本严格执行“会话证明校验 → 主企业与授权列表首项校验 → Grant 与完整多企业状态一次原子落盘 → 幂等 ACK → 输出不含秘密的完成事件”;同一会话重复 ACK 不改变授权集合,也不重复触发业务。完整接口和安全边界见 references/agent-login-api.md。
POSIX 系统由脚本强制登录状态目录和草稿目录为 0700、状态文件和草稿文件为 0600,草稿使用原子替换写入。Windows 部署必须另外使用每用户私有目录并配置等价 NTFS ACL;不能把状态或草稿目录放在所有用户可读的共享安装目录。
draft 和 query-invoices 都接受 --login-flow-id 或本机 --login-context-id。新草稿和直接查询默认使用当前活动企业;草稿创建时会固定其 nsrmc/nsrsbh/aggOrgId/accountId/sflx,之后切换活动企业不会改变旧草稿的销方,开票、结果查询、人脸认证和红冲仍使用草稿固定身份。固定身份不在当前 Grant 的授权列表时必须在联网前拒绝。不要从自然语言反推内部 ID,也不要先向用户索要非必需销方档案字段。
可选开票档案
invoice_profiles.json 不是生成草稿的必需条件。自然语言开票优先通过税局登录获取销方;本地档案只用于缓存常用商品、税收编码、税率、购方别名,以及离线测试场景。每次生成新的自然语言开票草稿时,只要本轮请求没有显式传入用户已确认的 --tax-code/--tax-name/--tax-rate,登录成功后都必须调用 invoice_classification MCP 查询并展示候选,不得直接复用历史草稿、本地默认商品或模型记忆中的商品编码。脚本按以下优先级读取可选档案:
- Skill 根目录:
qixiangyun-skill/invoice/qixiangyun-invoice-issuance-skill/invoice_profiles.json - 公共父目录:
/Users/xueds/Python/skills/qixiangyun-skill/invoice_profiles.json - 环境变量
QXY_INVOICE_PROFILE_FILE指定的文件
default_seller 是兼容字段,不是正常开票前置;真实开票优先使用网页最终选择的企业和
账号。buyers 只用于可选购方别名缓存,不得覆盖云抬头或用户本轮确认。
不要在档案中把某个税率或税收编码当成所有企业的默认值。税率和税收编码既可从智能
赋码候选中选择,也可由用户手工提供;最终值必须按当前登录企业的纳税人身份和可用
商品编码确认。项目名称既可输入自定义的 B,也可完整输入 *A*B:脚本最终传
spmc=A、xmmc=B,若 A 与所选税收分类名称冲突则停止生成草稿。
缺少销方时,返回 tax_login 卡点并只处理登录。登录完成后,缺少本轮显式确认的商品编码时自动使用 invoice_classification 服务的 query_invoice_tax_classification_auto 查询,参数包含登录获得的 nsrsbh、aggOrgId、可选 accountId 和商品名称 xmmc。智能赋码只提供候选,不管候选是否唯一,都必须展示编码、名称、税率和单位让用户确认本次使用哪一项;用户确认后再把对应的 --tax-code、--tax-name、--tax-rate 和可选 --unit 传回草稿命令。无可用结果时,引导用户确认商品名称或手工补充编码、名称、税率和单位。购方信息优先走 invoice_title 云抬头查询补全,只有多候选或专票缺购方税号时才追问用户。
主流程:自然语言开票
flowchart TD
A["用户输入:给 XXX 开 XXX 票"] --> C{"是否有有效税局登录态?"}
C -- "否" --> D["创建一次性 login_url 和本地 flow_id"]
D --> D1["Agent 只展示链接,并启动后台 wait-login"]
D1 --> D2["网页登录准备全部企业账号;后台原子保存并 ACK"]
D2 --> D3{"用户目标是否为当前活动企业?"}
D3 -- "否且已授权" --> D4["按名称和 KPY/BSY 消歧后直接切换"]
D3 -- "是" --> E["使用活动企业创建新草稿"]
D4 --> E
C -- "是且企业已确认" --> E
E --> B["解析开票信息:客户、商品、金额、票种"]
B --> F["云抬头补购方;无本轮确认商品编码时调用智能赋码"]
F --> F1{"是否已有本轮确认的商品编码?"}
F1 -- "否" --> F2["展示赋码候选并让用户确认"]
F1 -- "是" --> G1["校验金额、票种、购方税号、开票额度"]
F2 --> G1
G1 --> G{"是否通过校验?"}
G -- "否" --> H["返回错误或风险下一步"]
G -- "是" --> I["生成确认摘要,等待用户确认"]
I --> J["提交 issue_blue_invoice_auto"]
J --> K{"是否需要扫脸?"}
K -- "是" --> L["调用 face-qr 返回税务 APP 二维码"]
L --> M["用户扫码"]
M --> N["resume-after-face 查询状态并继续提交"]
K -- "否" --> O{"开票是否成功?"}
N --> O
O -- "否" --> P["返回失败原因或异步状态"]
O -- "是" --> Q["输出发票号码、日期、PDF/OFD/XML"]
1. 生成草稿
python3 scripts/invoice_issuance_workflow.py draft \
--text "给腾讯开软件服务费1000元,价税合计"
生成最终草稿前必须统一询问:“发票备注、收款人和复核人需要填写吗?均不填写可回复
‘都不填’。”用户回答后重新运行 draft --optional-fields-confirmed,并只为非空内容增加
--remark/--payee/--reviewer。未提供的 bz/skr/fhr 必须为空,且必须忽略档案中的
“财务部”“系统管理员”等旧默认值。内部来源订单号只写入 ly_ddbh,不得拼进备注。
如果用户只说“开 1000 元发票”,金额口径不明确,必须追问“价税合计还是不含税金额”。可在用户确认后传:
python3 scripts/invoice_issuance_workflow.py draft \
--text "给腾讯开软件服务费1000元" \
--amount-mode total
draft 返回:
waiting_for_user_input=true:包含missing_fields、question、draft_idwaiting_for_user_input=false:包含confirmation_summary、payload_preview、draft_id
草稿生成时会调用销方企业信息和开票额度 MCP 校验;认证失败、登录态异常、业务失败、额度不足或税局不稳定时,脚本会返回 waiting_for_user_input=true 并给出下一步,不会改用其他通道。只做本地草稿演练时可设置 QXY_INVOICE_SKIP_PREFLIGHT=1 跳过预检。
2. 确认并开票
真实开票前必须把 confirmation_summary 复述给用户,并得到明确确认。
python3 scripts/invoice_issuance_workflow.py issue \
--draft-id 草稿ID \
--login-context-id Agent内部会话ID \
--confirmed "确认开票"
确认文本为空或不包含“确认/同意/可以开票”等明确意图时,脚本只返回草稿预览,不调用开票 MCP。
真实开票、红字申请、登录会话创建和人脸二维码创建等无法证明幂等的写操作,遇到超时、
断连或响应丢失时不得由传输层自动重放。真实开票结果不确定时,应先使用原草稿中的
ly_ddbh 查询开票结果;未确认上一请求未生效前不得再次提交开票。
如果开票 MCP 返回 720007、扫脸或人脸认证提示,脚本会自动调用 face 服务获取二维码,并返回:
face.tax_app.rzid/face.tax_app.qrcode:电子税务局 APP 扫脸认证face.national_id_app.rzid/face.national_id_app.qrcode:国家网络身份认证 APP 扫脸认证face.*.image_path:Skill 使用内置纯 Python 实现生成的本地 PNG 绝对路径,兼容 Windows、Linux 和 macOS,无需安装qrcode、Pillow 或系统二维码工具face.*.media_directive/face.openclaw_media:OpenClaw 可识别的图片输出标记
在 OpenClaw 对话中,拿到 media_directive 后必须将其原样放在回复的独立一行。回复第一行提示用户使用税务 APP 扫码,第二行直接输出类似 MEDIA:/绝对路径/face_qr/tax-app-RZ001.png 的标记。
MEDIA: 行不能放进代码块,也不要把 qrcode、gwEwm 或 Base64 原文直接展示给用户;这些字段是二维码内容,不是 OpenClaw 可渲染的图片。
人脸工具和发票查询工具必须携带与开票草稿一致的 accountId/aggOrgId 上下文。优先通过 --draft-id 让脚本自动读取草稿中的账号字段;不要只传 nsrsbh,否则容易出现 720016 登录信息有误。
扫码后可单独查询状态:
python3 scripts/invoice_issuance_workflow.py face-status \
--nsrsbh 销方纳税人识别号 \
--rzid face返回的rzid \
--draft-id 草稿ID \
--login-context-id Agent内部会话ID
slzt=1 表示未扫脸,slzt=2 表示扫脸成功,slzt=3 表示二维码过期。按完整链路续跑时使用 resume-after-face:脚本会先查询扫脸状态,成功后自动继续提交同一草稿;未扫脸或二维码过期时不会提交开票。
python3 scripts/invoice_issuance_workflow.py resume-after-face \
--draft-id 草稿ID \
--nsrsbh 销方纳税人识别号 \
--rzid face返回的rzid \
--login-context-id Agent内部会话ID \
--confirmed "确认开票"
二维码过期时重新获取二维码:
python3 scripts/invoice_issuance_workflow.py face-qr \
--nsrsbh 销方纳税人识别号 \
--kpyxm 开票人姓名 \
--draft-id 草稿ID \
--login-context-id Agent内部会话ID
3. 查询开票结果
异步处理、扫脸后续跑或用户要求“查询开票结果”时,优先使用 workflow 的草稿查询命令:
python3 scripts/invoice_issuance_workflow.py query-result \
--draft-id 草稿ID \
--login-context-id Agent内部会话ID
该命令会从草稿 payload 自动读取 nsrsbh、ly_ddbh、accountId、aggOrgId,默认调用 query_invoice_details_auto 查询同一来源订单的发票明细。不要让用户手动执行裸 mcp_client.py --tool query_invoice_list_auto ... 后再人工补 accountId/aggOrgId;这会破坏开票上下文,容易触发 720016 登录信息有误。
需要按日期范围查列表时才使用:
python3 scripts/invoice_issuance_workflow.py query-result \
--draft-id 草稿ID \
--login-context-id Agent内部会话ID \
--mode list \
--kprqq 2026-06-04 \
--kprqz 2026-06-04
用户直接要求“查询本月已开具发票明细/列表”且不是查询某个草稿结果时,先创建一次性登录链接:
python3 scripts/invoice_issuance_workflow.py query-invoices \
--period current-month \
--login-context-id Agent内部会话ID
Agent 只渲染返回的 login.user_interaction.message,同时在内部后台运行
login.agent_handoff.waitArgv。收到 qxy.agent_login.completed 后,用事件中的内部
flow_id 续跑:
python3 scripts/invoice_issuance_workflow.py query-invoices \
--login-flow-id Agent内部flow_id \
--login-context-id Agent内部会话ID \
--period current-month
如果用户明确指定日期范围,传入:
python3 scripts/invoice_issuance_workflow.py query-invoices \
--login-flow-id Agent内部flow_id \
--login-context-id Agent内部会话ID \
--kprqq 2026-06-01 \
--kprqz 2026-06-24
query-result 只有查到 invoice_number、issue_date 或 pdf_url/ofd_url/xml_url 时才返回 issued=true;仅返回 2000 成功码但没有发票号码或版式文件时,仍按“处理中/未查到结果”处理。
4. 销方全额红冲
先按蓝票草稿,或按“发票号码 + 开票日期”查询并核验原蓝票:
python3 scripts/invoice_issuance_workflow.py red-draft \
--blue-draft-id 原蓝票草稿ID \
--reason-code 01 \
--login-context-id Agent内部会话ID
也可把 --blue-draft-id 换成 --invoice-number 原发票号码 --issue-date 2026-08-05。
脚本会核验销方、票种、金额和原票状态;数电票使用 lzFphm + fplxdm(030/032),其他
受支持票种使用查询得到的 zz_fpdm + zz_fphm。核验完成后分三步执行:
python3 scripts/invoice_issuance_workflow.py red-apply \
--red-state-id 红冲状态ID \
--login-context-id Agent内部会话ID \
--confirmed "确认红冲"
python3 scripts/invoice_issuance_workflow.py red-status \
--red-state-id 红冲状态ID \
--login-context-id Agent内部会话ID
python3 scripts/invoice_issuance_workflow.py red-issue \
--red-state-id 红冲状态ID \
--login-context-id Agent内部会话ID \
--confirmed "确认开具红票"
hzkjBz=Y 表示红票已自动开具,禁止再调用 red-issue;只有明确为 N 时,才可在
第二次确认后开票。710021 只查询已有记录,不重复申请。红字申请或红票开具出现超时、
断连、响应丢失时,后续只能运行 red-status 对账,禁止自动重放。红冲状态保存在包外
0700 私有目录和 0600 文件中;同企业同账号重新登录后,可将新 --login-flow-id
连同原 --login-context-id 传给 red-status/red-apply/red-issue 继续查询或处理。
红票版式中的原蓝票号码和红字确认单编号由税局自动生成;红票接口不接受
bz/skr/fhr,只能通过原蓝票开具前的上述询问避免附带自定义备注、收款人和复核人。
5. 输出结果
开票成功时,Agent 私有结果包含:
invoice_numberinvoice_codeissue_datepdf_url/ofd_url/xml_urluser_download_message:已校验、可直接面向用户渲染的 Markdown 下载区mcp_raw_summary
面向用户只说明开票状态、发票号码/代码/日期,并原样渲染非空的
user_download_message。脚本会在开票响应没有版式地址时,自动只读查询同一草稿一次;
查询后仍为空,只能说明“版式文件下载地址尚未返回”,不能写“链接已附上”。不得展示
字段名、mcp_raw_summary、草稿 ID、请求 ID、内部查询参数或原始记录;不在
user_download_links 中的非 HTTPS/异常地址不得转成链接。
如果 MCP 返回扫脸、登录态、额度不足、购方异常、税局不稳定或异步处理中,脚本会停止流程并返回结构化下一步,不能切换到旧登录链路或手写 HTTP。2001 或“处理中”只表示开票进入异步处理,不能对用户表述为“发票已提交成功”或“开票成功”;只有拿到发票号码、开票日期或 PDF/OFD/XML 链接后,才算开票成功。
业务规则
- 用户未明确金额口径时,必须追问“价税合计”还是“不含税金额”。
- 普票允许购方税号为空,但确认摘要必须展示“购方税号为空”。
- 专票必须有购方税号;缺失时不得提交。
- 商品/服务名称缺失时必须追问;有名称但缺少本轮确认的税收编码时必须调用智能赋码并让用户确认,不得直接采用
default_product或编造编码。 - 开票、红冲都属于高风险动作,调用真实 MCP 前必须二次确认。
- 不在回复和日志中输出
QXY_API_KEY、其中的 appkey/secret、验证码或完整私密业务 payload。 - 不向用户展示
flow_id、服务端request_id、原始会话证明、Agent Grant、waitCommand、Agent 会话标识或原始工具 JSON。 - 不接受任意
callbackUrl;跨平台通知只能由 Agent 自己消费wait-login事件后完成。 .env、invoice_profiles.json、.generated/和所有运行态文件都不得提交到版本控制;运行态必须位于包外私有根目录。- 本地单用户首次配置必须通过
--check-config --allow-agent-credential-configuration显式开启,并原样使用返回的
configure_credentials.py --agent-stdin --local-single-userargv 契约;集中托管、多租户
和企业共享环境不得传该 opt-in,必须使用平台 Secret,且不得共用 Skill.env。
原子 MCP 工具
所有业务调用只能通过 bundled scripts:
scripts/invoice_issuance_workflow.pyscripts/mcp_client.py
禁止直接使用 curl、requests、OpenAPI、网页浏览或手写 HTTP 请求调用企享云开票接口。服务别名和工具映射见 references/mcp-services.md。
常用原子命令:
python3 scripts/mcp_client.py --list-services
python3 scripts/mcp_client.py --check-config
python3 scripts/mcp_client.py --service blue_invoice --describe-tool issue_blue_invoice_auto
python3 scripts/mcp_client.py --login-flow-id Agent内部flow_id --tool query_invoice_issuance_quota_auto --args '{"nsrsbh":"纳税人识别号","aggOrgId":"企业ID","orgId":"企业ID","accountId":"账号ID"}'
python3 scripts/mcp_client.py --login-flow-id Agent内部flow_id --tool query_invoice_tax_classification_auto --args '{"nsrsbh":"纳税人识别号","xmmc":"商品或项目名称","aggOrgId":"企业ID","accountId":"账号ID"}'
python3 scripts/mcp_client.py --login-flow-id Agent内部flow_id --tool query_invoice_list_auto --args '{"nsrsbh":"纳税人识别号","kprqq":"2026-06-01","kprqz":"2026-06-24","aggOrgId":"企业ID","accountId":"账号ID"}'
python3 scripts/mcp_client.py --login-flow-id Agent内部flow_id --tool issue_blue_invoice_auto --args @/tmp/invoice-data.json
--login-flow-id 只能由 Agent 从私有完成事件或草稿关联中自动追加,不能让用户手工保存或
输入。脚本只用它回读私有 Grant;不存在 --agent-grant 参数,也不得把 Grant 拼入命令。
支持服务:
agent_login:一次性税局登录会话创建、查询和确认;由 bundled scripts 内部使用invoice_title:购方开票抬头查询invoice_classification:根据商品或项目名称查询税收分类编码face:开票人脸认证二维码和认证结果查询enterprise_info:企业信息查询、开票额度查询invoice_inquiry:已开发票列表/明细查询blue_invoice:蓝票、农产品收购发票、报废产品收购发票开具red_invoice:红字信息表申请/查询、红字发票开具