# 首个迭代工程详细设计 状态:设计完成,待应用实现与集成验证。依据:[需求规格](../requirements/iteration-01-requirements.md)、[验收标准](../requirements/iteration-01-acceptance.md)。 ## 1. 模块与运行进程 采用模块化应用,API、Agent worker、后台 worker 分别部署与扩容。模块通过应用服务调用,跨进程使用持久化任务及领域事件。数据库事务属于应用服务,HTTP handler 与 Agent 工具不直接修改业务表。 | 模块 | 所有权 | 对外服务 | |---|---|---| | identity | 租户、店铺、应用、员工授权、客户身份关联 | authenticate、authorize、resolve_subject | | channels | 渠道绑定、Inbox、消息归一化、回调投递 | accept_message、deliver_event | | conversations | 会话、消息、控制权、输入事件 | append_message、take_over、release_control | | after_sales | 工单、方案、确认、审批、数量占用 | create_proposal、confirm、decide、prepare_operation | | integrations | OMS 连接器、外部操作、结果查询 | submit_exchange、reconcile_operation | | knowledge_memory | 文档发布、检索、客户记忆与删除状态 | retrieve、read_memory、update_memory、delete_memory | | agent_runtime | run、等待、执行租约、图版本 | enqueue、resume、cancel、execute | | model_governance | 路由、调用预算、实际用量 | reserve_budget、invoke、settle_usage | | platform_governance | 发布清单、Outbox、审计、运行配置 | publish、audit、dispatch | API 进程处理认证、参数验证、短事务及 SSE。模型和外部网络请求均设置截止时间;数据库事务内不等待这些请求。Agent worker 处理推理和图推进,后台 worker 处理文档导入、记忆提取、Outbox、回调、外部结果查询。长任务与交互任务使用独立并发额度。 ## 2. 数据库设计约定 MySQL 是业务状态、授权、执行权与操作记录的事实来源。Redis 分别提供缓存、持久检查点及记忆索引;Milvus 保存可重新生成的知识向量。外部订单投影只是查询加速数据。 主键使用应用生成的 UUID,MySQL 保存为 BINARY(16),API 输出标准 UUID 字符串。时间使用 UTC DATETIME(6),业务版本使用 BIGINT UNSIGNED,数量使用正整数;金额如需扩展使用最小货币单位整数并带 currency。业务状态使用 VARCHAR(32),在服务和数据库 CHECK 中限制合法值。 租户数据必含 tenant_id。关联对象使用 UNIQUE(tenant_id,id) 与复合外键 (tenant_id,parent_id),阻止跨租户关联。查询统一接收服务器建立的 AuthContext,禁止仅凭 id 查询租户对象。删除使用显式生命周期操作;审批和审计记录不覆盖历史。 通用可变实体包含 created_at、updated_at、version;业务更新带 expected_version 并验证受影响行数。列表采用 (created_at,id) 游标分页,默认 20、上限 100。JSON 用于不可变方案内容、引用和事件数据;授权字段、状态、版本及调度条件使用独立列。 ### 2.1 身份、会话与规则表 | 表 | 关键字段 | 唯一约束与索引 | |---|---|---| | tenants | id、status、quota_policy_id | 主键 id | | stores | tenant_id、id、name、status | tenant_id,id | | client_apps | tenant_id、id、credential_ref、status | tenant_id,id;凭据引用保存在密钥系统 | | app_store_grants | tenant_id、app_id、store_id、scope | tenant_id,app_id,store_id,scope | | staff_grants | tenant_id、staff_id、store_id、permission、status | tenant_id,staff_id,store_id,permission | | customer_subjects | tenant_id、id、status、memory_epoch、memory_revision、consent_version | tenant_id,id | | channel_bindings | tenant_id、id、store_id、app_id、key_id、secret_ref、status | tenant_id,id | | customer_identities | tenant_id、binding_id、external_user_id、subject_id、verification_id | tenant_id,binding_id,external_user_id | | identity_verifications | tenant_id、id、subject_id、method、verified_at、expires_at、evidence_ref | tenant_id,id;证据脱敏与限制访问 | | conversations | tenant_id、id、store_id、subject_id、binding_id、control_owner、control_version、active_run_id | tenant_id,subject_id,created_at,id | | messages | tenant_id、id、conversation_id、sequence、role、content_ref、control_version | tenant_id,conversation_id,sequence | | input_events | tenant_id、id、conversation_id、actor_id、event_type、payload、payload_hash、consumed_by | tenant_id,id | | rule_versions | tenant_id、rule_id、version、status、effective_at、definition、document_version_id | tenant_id,rule_id,version | | knowledge_versions | tenant_id、id、document_id、version、status、object_ref、content_hash | tenant_id,document_id,version | | releases | tenant_id、id、graph_version、state_schema_version、prompt_version、tool_version、knowledge_manifest、rule_manifest、model_route_version | tenant_id,id | 渠道客户标识使用大小写敏感比较。身份关联只接受两端验证通过的证明,并在同一事务更新映射和审计。撤销身份关联立即影响新请求,已有业务记录保留原主体及授权审计。 ### 2.2 售后与外部操作表 | 表 | 关键字段 | 唯一约束与索引 | |---|---|---| | order_projections | tenant_id、connector_id、external_order_id、subject_id、source_version、observed_at、payload | tenant_id,connector_id,external_order_id | | tickets | tenant_id、id、store_id、subject_id、conversation_id、status、current_proposal_id、version | tenant_id,subject_id,created_at,id;tenant_id,store_id,status,created_at,id | | proposals | tenant_id、id、ticket_id、current_version、created_by | tenant_id,id | | proposal_versions | tenant_id、proposal_id、version、order_id、item_id、quantity、reason、rule_manifest、order_version、content_hash | tenant_id,proposal_id,version | | confirmations | tenant_id、proposal_id、proposal_version、subject_id、input_event_id、confirmed_at | tenant_id,proposal_id,proposal_version | | approvals | tenant_id、id、proposal_id、proposal_version、submitted_by、status、decided_by、decision_reason、version | tenant_id,proposal_id,proposal_version;tenant_id,status,created_at,id | | item_guards | tenant_id、connector_id、order_id、item_id、version | tenant_id,connector_id,order_id,item_id | | reservations | tenant_id、id、operation_id、connector_id、order_id、item_id、quantity、status | tenant_id,operation_id;tenant_id,connector_id,order_id,item_id,status | | external_operations | tenant_id、id、proposal_id、proposal_version、action_type、request_hash、status、external_id、lease_token、lease_until、next_check_at、last_error | tenant_id,proposal_id,proposal_version,action_type;status,next_check_at,id | proposal_versions 的业务内容不可修改。只有 DRAFT 或 NEEDS_REVISION 允许创建修订;已确认且等待审批的方案需要显式撤回到修订流程,作废旧审批并清除其执行资格,然后生成新版本。已有外部操作时禁止修订。客户确认、主管审批、准备操作都检查 tickets.current_proposal_id 与 proposals.current_version。 item_guards 是每个订单明细的稳定加锁行,首次插入处理唯一键竞争后重新读取并加锁。reservations 状态为 HELD、CONSUMED、RELEASED:未知结果保持 HELD;外部受理后转 CONSUMED;外部确定失败且不会迟到执行时转 RELEASED。已受理数量由 OMS 当前可申请数量反映,计算本地可提交数量时只减尚未被 OMS 确认受理的 HELD,禁止重复扣减。 ### 2.3 运行与可靠投递表 | 表 | 关键字段 | 唯一约束与索引 | |---|---|---| | agent_runs | tenant_id、id、conversation_id、status、release_id、version、lease_token、lease_until、checkpoint_ref、next_attempt_at、deadline_at | status,next_attempt_at,id;tenant_id,conversation_id,created_at,id | | run_waits | tenant_id、run_id、interrupt_id、expected_type、proposal_id、proposal_version、run_version、status、input_event_id | tenant_id,run_id,interrupt_id | | run_events | tenant_id、run_id、sequence、type、payload、created_at | tenant_id,run_id,sequence | | api_idempotency | tenant_id、app_id、actor_id、route、key、request_hash、status、resource_id、response、expires_at | tenant_id,app_id,actor_id,route,key | | channel_inbox | tenant_id、binding_id、external_message_id、payload_hash、payload、status、next_attempt_at | tenant_id,binding_id,external_message_id | | outbox_events | event_id、tenant_id、aggregate_id、aggregate_version、event_type、schema_version、payload、status、next_attempt_at | event_id;status,next_attempt_at,event_id | | consumer_receipts | consumer_name、event_id、processed_at | consumer_name,event_id | | webhook_deliveries | tenant_id、id、subscription_id、event_id、status、attempt_count、next_attempt_at | tenant_id,subscription_id,event_id;status,next_attempt_at,id | | memory_jobs | tenant_id、id、subject_id、epoch、revision、source_event_id、status | tenant_id,subject_id,epoch,source_event_id | | model_attempts | tenant_id、id、run_id、provider_request_id、reserved_tokens、actual_tokens、status、pricing_version | tenant_id,id;provider_request_id 按供应商范围去重 | | audit_records | tenant_id、id、actor_id、action、resource_type、resource_id、request_id、before_version、after_version、created_at | tenant_id,resource_id,created_at,id | api_idempotency 增加 actor_id,防止同一 H5 应用中的不同客户复用 key 读取他人响应;这进一步限定需求中的应用级范围。过期 API 记录清理不影响外部操作的永久业务去重。输入正文包含敏感信息时加密存储并按照数据保留策略清理。 ```mermaid erDiagram tenants ||--o{ stores : owns stores ||--o{ channel_bindings : exposes customer_subjects ||--o{ customer_identities : verifies customer_subjects ||--o{ conversations : uses conversations ||--o{ agent_runs : executes conversations ||--o{ tickets : creates tickets ||--o{ proposals : contains proposals ||--|{ proposal_versions : versions proposal_versions ||--o| confirmations : confirmed proposal_versions ||--o| approvals : reviewed proposal_versions ||--o{ external_operations : performs external_operations ||--o| reservations : reserves agent_runs ||--o{ run_waits : waits agent_runs ||--o{ run_events : streams ``` ## 3. 事务与并发控制 统一加锁顺序:当前授权控制行 → conversation → run → ticket → proposal → approval → item_guard → operation。按需取用,多个同类资源按主键排序。短事务发生并发冲突时,由调用方使用同一幂等键进行有界重试;参数、权限、规则错误直接返回。 ### T1 输入受理与执行创建 验签或验证登录身份后,事务插入 Inbox / 幂等记录,锁定 conversation,保存 input_event。无 active_run 时创建 QUEUED run 和 Outbox;存在等待 run 时只接受该等待类型的输入。接管会话只保存供人工处理的输入。提交事务后返回受理结果。RabbitMQ 只是唤醒信号,定时扫描 MySQL 的到期任务可补充遗漏的唤醒。 ### T2 确认与审批 确认事务校验客户、当前方案版本、当前规则有效性,写 confirmation、审批记录、工单 WAITING_REVIEW、审计及 Outbox。审批事务核验主管权限、提交人分离、方案版本与客户确认,写不可重复决定、工单状态及 Outbox。事件驱动等待 run 恢复,调用端无需伪造恢复参数。 ### T3 准备外部操作 先在事务外读取 OMS 最新版本。事务内锁定上述相关记录,校验权限、会话控制权、审批、规则撤销状态及订单明细占用,建立 HELD reservation、PREPARED operation、PROCESSING 工单和 Outbox。提交后连接器携带 stable operation_id 与 expected_order_version 调用 OMS。外部条件更新处理读取和写入之间的订单变化。 权限撤销、规则撤销与操作准备使用相同的对应授权或规则行锁,确定提交顺序。准备操作事务是平台的业务授权提交点;提交后的操作作为已授权业务继续跟踪,接管与取消不得将其解释为尚未开始。对已提交操作提出终止要求需要 OMS 提供独立撤销流程。 ### T4 外部结果登记 OMS 返回明确受理后,锁定 operation 和关联 ticket,以当前版本更新外部标识、CONSUMED reservation、审计和 Outbox。响应超时转 UNKNOWN,工单 RESULT_UNKNOWN,保留占用并调度查询。收到履约完成回调可直接完成工单,即使此前处于 RESULT_UNKNOWN;检查外部版本,晚到受理响应不能覆盖已完成结果。 查询 NOT_FOUND 不足以证明原提交不会迟到。只有 OMS 对该 operation_id 记录了不可再执行的终止结果,才释放占用。重发始终使用同一 operation_id 和 request_hash;缺少持久幂等、条件更新或结果查询能力的连接器禁止自动执行写操作,转人工处理。 ### T5 接管、取消与消息发布 接管事务锁 conversation,增加 control_version、更新 owner,取消未完成 run 并记录事件。操作准备和 Agent 对客消息入库必须在同一 conversation 锁下核验版本。发布通道按会话串行处理控制事件和消息,对旧版本尚未发送的内容进行过滤。已交给网络的字节可能在接管后到达,H5 依据 control_version 丢弃旧版本内容;外部渠道只承诺接管后不再受理新的 Agent 发送动作。 取消工单与准备操作争用同一 ticket 锁;已有 operation 时返回 OPERATION_IN_PROGRESS。取消 run 只终止后续图执行,不撤销外部业务。人工释放控制权后,新客户输入创建新 run。 ## 4. 对外 API 基础路径 /openapi/v1,员工配置与平台治理使用 /admin/v1。H5 使用安全登录会话并执行 CSRF 校验;服务调用使用限权访问令牌;外部回调使用签名。AuthContext 包含 tenant_id、app_id、actor_type、actor_id、subject_id、store_ids、scopes、request_id,由认证层创建,禁止模型或请求正文提供。 所有写接口要求 Idempotency-Key;变更已有对象同时要求 expected_version。JSON 禁止未知业务字段,数量为正整数。错误响应固定为 {code,message,request_id,details,retryable},details 不包含其他租户对象信息。查询越权对象与不存在对象统一返回 404。 | 方法与路径 | 主要输入 | 权限与响应 | |---|---|---| | POST /conversations | channel_binding_id | conversations:write;201 conversation_id、version | | POST /conversations/{id}/runs | message、client_message_id | 客户本人;202 run_id、status、events_url | | GET /orders | cursor、limit | 当前客户订单;员工需 orders:read 与店铺范围 | | GET /orders/{id} | 无 | 返回当前订单、source_version、observed_at | | POST /after-sales/proposals | conversation_id、order_id、item_id、quantity、reason | 售后创建权限;201 proposal_id、proposal_version、ticket_id、引用 | | POST /after-sales/proposals/{id}/revisions | expected_version、业务字段 | 当前主体或授权客服;201 新版本,作废旧确认与审批资格 | | POST /after-sales/proposals/{id}/confirm | proposal_version、expected_ticket_version | 当前客户确认;200 confirmation_id、approval_id、ticket_status | | GET /approvals | status、cursor、limit | 审批权限与店铺过滤 | | POST /approvals/{id}/decisions | expected_version、proposal_version、decision、reason | 当前主管且非提交人;200 决定结果 | | GET /tickets/{id} | 无 | 本人或授权员工;当前状态、版本与可执行动作 | | POST /tickets/{id}/cancel | expected_version、reason | 当前客户或授权客服;200 当前状态 | | POST /conversations/{id}/takeover | expected_control_version | 授权客服;200 owner、control_version | | POST /conversations/{id}/release | expected_control_version | 当前接管客服或主管;200 control_version | | POST /conversations/{id}/messages | text、expected_control_version | 接管客服;201 message_id | | GET /runs/{id} | 无 | 当前主体或授权员工;状态、等待类型与版本 | | GET /runs/{id}/events | Last-Event-ID | SSE,按 run 内 sequence 续传 | | POST /runs/{id}/inputs | interrupt_id、expected_run_version、answer | 当前客户;201 input_event_id,后台自动请求恢复 | | POST /runs/{id}/resume | input_event_id、interrupt_id、expected_run_version | 内部恢复权限;202,同一事件幂等 | | POST /runs/{id}/cancel | expected_version、reason | 当前客户或授权员工;200 状态 | | GET /me/memories | cursor、limit | 本人;当前 epoch 的可读记忆 | | PUT /me/memories/{id} | expected_revision、content | 本人;200 新 revision | | DELETE /me/memories | expected_epoch | 本人;200 新 epoch,后台清理旧内容 | | POST /webhooks/v1/channels/{binding_id}/messages | 签名消息 envelope | 202 receipt_id;路径独立于基础路径 | 规则发布使用 POST /admin/v1/rules/{id}/versions,激活使用 POST /admin/v1/releases,撤销使用 POST /admin/v1/rules/{id}/versions/{version}/revoke;均需商家配置权限、expected_version 与审计。知识导入通过受控对象上传后 POST /admin/v1/knowledge/imports 创建异步任务。配置发布必须引用已完成索引的知识版本。 Webhook 订阅通过 /admin/v1/webhook-subscriptions 管理,重投使用 POST /admin/v1/webhook-deliveries/{id}/retry。租户、应用、店铺与角色管理遵守 identity 的同一授权规则;平台配置权限不自动授予客户数据读取权限。 | HTTP | code | 调用方行为 | |---|---|---| | 401 / 403 | UNAUTHENTICATED / FORBIDDEN | 完成认证或申请相应授权 | | 404 | RESOURCE_NOT_FOUND | 不重试相同查询 | | 409 | IDEMPOTENCY_CONFLICT | 检查请求键和参数 | | 409 | PROPOSAL_VERSION_CONFLICT / VERSION_CONFLICT | 重新读取资源再执行用户动作 | | 409 | CONVERSATION_WAITING / HUMAN_CONTROLLED | 展示等待动作或人工状态 | | 409 | OPERATION_IN_PROGRESS / QUANTITY_CONFLICT | 查询工单或调整申请 | | 422 | RULE_NOT_SATISFIED / INVALID_INPUT_EVENT | 展示业务原因与修正字段 | | 429 | TENANT_QUOTA_EXCEEDED | 遵守 Retry-After | | 503 | DEPENDENCY_UNAVAILABLE | 保留幂等键,有界重试 | EXTERNAL_RESULT_UNKNOWN 是已受理工单的业务状态提示,查询接口返回 200 并提供 operation_id 和下一次检查时间,客户端不得因此创建新申请。SSE 返回 event_id、event_type、sequence、control_version;过期游标在建立流之前返回 410 EVENT_CURSOR_EXPIRED,客户端查询当前快照。 ## 5. Webhook 与事件协议 渠道签名字符串为 timestamp + 换行 + nonce + 换行 + HTTP 方法 + 换行 + 原始路径 + 换行 + SHA256(raw_body)。使用 HMAC-SHA256,头部提供 X-Key-Id、X-Timestamp、X-Nonce、X-Signature。签名常量时间比较,时间允许窗口为 300 秒,nonce 在窗口内去重;绑定决定租户及应用。业务重投使用新 nonce 和同一 external_message_id。密钥轮换保留明确的双密钥有效期。 入站 envelope 包含 external_message_id、external_user_id、occurred_at、type、payload;type 为 message、proposal_confirmation 或 clarification。客户动作只在渠道确实提供已认证用户身份且本地映射有效时受理,普通聊天文本不转换为确认记录。 领域事件示例: ```json { "event_id": "01951000-0000-7000-8000-000000000001", "event_type": "after_sale.approved", "schema_version": 1, "tenant_id": "01951000-0000-7000-8000-000000000002", "aggregate_type": "ticket", "aggregate_id": "01951000-0000-7000-8000-000000000003", "aggregate_version": 4, "occurred_at": "2026-09-19T12:00:00Z", "trace_id": "8c37a78437a84603a629b45ea6257f97", "payload": {"proposal_id": "01951000-0000-7000-8000-000000000004", "proposal_version": 1} } ``` | 事件 | 生产者 | 消费行为 | |---|---|---| | conversation.input_received | channels / conversations | 唤醒对应 run | | after_sale.proposal_confirmed | after_sales | 恢复等待确认的 run,通知审批 | | after_sale.approved / rejected | after_sales | 恢复等待审批的 run,或调度人工流程的执行 | | after_sale.operation_prepared | after_sales | 提交指定 operation | | after_sale.result_changed | integrations | 更新通知与工单查询投影 | | conversation.taken_over | conversations | 终止后续 Agent 动作与旧版本输出 | | memory.deleted | knowledge_memory | 清理旧 epoch 索引和内容 | | knowledge.published | knowledge_memory | 更新可用发布版本 | Outbox 发布采用至少一次投递,只有 broker 确认且路由有效才标记已发送。消费者在业务事务中插入 consumer_receipts 并更新业务,提交后 ACK。外部 I/O 使用独立 operation 或 delivery 状态机;收据不能在外部提交前使业务失去恢复入口。 回调复用相同签名规范,额外提供 delivery_id。自动重试采用带随机扰动的指数退避,最多 12 次且最长 24 小时,超过限制进入人工处理队列。接收方按 event_id 去重,按 aggregate_version 处理乱序。订阅地址限制 HTTPS,解析与连接时均阻止内网、环回及链路本地地址,禁止自动跟随重定向,凭据保存在密钥系统。 ## 6. LangGraph 状态与执行流程 图状态字段:run_id、conversation_id、release_id、state_schema_version、intent、candidate_order_ids、selected_order_id、missing_fields、rule_refs、proposal_id、proposal_version、interrupt_id、input_event_id、operation_id、control_version、step_count、token_budget_remaining、last_error_code。身份从运行时重新建立的 AuthContext 注入;checkpoint 不作为权限证据。 | 节点 | 输入与产物 | 转移条件 | |---|---|---| | load_context | 读取当前身份、控制权、发布清单与授权记忆 | 无权限结束;人工控制时取消 | | classify_intent | 结构化意图与必需字段 | 问答进入检索;换货进入查单;人工请求触发接管请求 | | resolve_order | 权限内订单候选 | 不唯一或缺信息进入 await_input | | await_input | 保存等待类型、interrupt_id 与 run_version | 有效输入事件恢复到 resolve_order | | retrieve_policy | 当前商家、发布版本的文档引用 | 无依据时请求人工;有依据进入 evaluate_policy | | evaluate_policy | 确定性业务校验结果 | 拒绝则答复;符合则 create_proposal | | create_proposal | 调用共享服务,保存方案引用 | 进入 await_confirmation | | await_confirmation | 客户指定版本确认事件 | 确认有效进入 await_approval | | await_approval | 指定版本审批事件 | 拒绝答复;批准进入 prepare_operation | | prepare_operation | 调用共享应用服务复核并创建唯一操作 | 变化请求修订;成功交由后台执行 | | respond | 从业务事实生成答复并附引用 | 保存带控制版本的消息,完成 run | interrupt 前保存 run_waits 与持久检查点。若 MySQL 等待记录已保存但检查点保存失败,run 标记恢复异常并暂停,恢复协调器检查两侧版本后继续;不能向客户端宣称可以恢复一个不存在的检查点。输入可能先于图进入等待到达,因此恢复协调器扫描未消费的有效事件,不依赖一次性通知。 恢复使用原 thread_id(服务器按 tenant_id/run_id 构造)和原 release_id。可能重复执行的节点只能执行查询或调用幂等应用服务。恢复前核验事件所属租户、主体、等待类型、方案版本、消费状态和当前 run_version;同一事件绑定一个等待记录并以 CAS 推进状态。运行取消与恢复争用同一 run 行锁,已取消任务拒绝恢复。 租约由 MySQL 发放,每次重新领取增加 lease_token。检查点写入使用每次执行独立 checkpoint namespace;失去租约的 worker 不能更新 MySQL 中已接受的 checkpoint_ref。接管、取消、业务写入和最终答复均校验 lease_token 与 control_version,过期 worker 产生的检查点不被恢复入口采用。 图默认最多 20 个节点步骤,单次活跃执行截止时间 120 秒,单次模型调用截止时间 30 秒;等待用户与审批的时间不计入活跃执行时长。超限保存 FAILED 与错误原因,工单保持实际业务状态。等待业务失效或超期通过业务服务关闭,不能凭模型决定释放未知外部操作。 ## 7. Agent 工具边界 | 工具 | 模型可提供的参数 | 服务端强制行为 | |---|---|---| | search_orders | 查询条件、分页游标 | 注入主体与店铺范围,限制返回条数 | | get_order | order_id | 校验归属,返回来源版本 | | retrieve_policy | question、product_type | 注入 tenant 与知识版本过滤,返回引用 | | evaluate_exchange | order_id、item_id、quantity、reason | 确定性规则计算,返回拒绝码或依据 | | create_exchange_proposal | 当前订单明细、数量、理由 | 应用服务校验,节点重放复用持久化命令标识 | | get_ticket | ticket_id | 校验主体,返回实际进度 | | request_human | reason | 登记接管请求,等待客服取得控制权 | 确认、审批、执行授权、身份关联和记忆删除不开放为模型自行决定的工具。prepare_operation 节点由图控制调用应用服务,并验证已保存的业务证据。工具返回不包含其他客户字段、密钥或可执行指令。工具参数 JSON schema 在工程中与 API 请求模型复用,约束由服务执行。 ## 8. 记忆、检索与模型资源 记忆写入按 customer_subject 串行处理,写前与提交后核验 epoch、revision、consent_version。更正或删除增加版本,使迟到提取任务失效。读取同时检查 MySQL 当前 epoch,持久 Redis 故障时不使用不确定版本的个性化内容。每条记忆保存来源、更新时间及授权依据。 知识导入采用对象存储原文 → 解析 → 分段 → Embedding → Milvus → 检索验证 → 发布的任务链,任务以 document_version_id 和阶段去重。检索过滤 tenant_id、store 范围、发布版本及文档权限;缓存键包含这些维度。删除或撤销立即改变可读状态,后台异步清理向量。 模型入口按供应商全局额度、租户额度、应用额度、客户额度执行准入;使用估算输入加最大输出预留 token,实际完成后按 model_attempt_id 结算。超时且用量未知的尝试保留待核对状态。每次真实重试创建独立 attempt,不能重复结算同一 attempt。 交互队列按租户轮转并限制各租户运行数量,全局供应商信号量控制外呼,检索与文档任务使用独立并发池。API 连接池总量以所有副本进程之和核算,保留 MySQL 运维连接。SSE 使用有界发送缓冲,慢客户端断开后通过事件游标恢复,禁止无限累计内存。 ## 9. 发布与验证 发布清单锁定图、状态 schema、Prompt、工具、规则、知识、模型路由及依赖版本。新 run 使用当前发布,等待 run 使用原发布;安全撤销与权限变化始终依据当前状态。数据库迁移采用兼容新增、数据迁移、切换读取、最后清理的顺序,运行中的旧版本退出前保留所需字段及执行制品。 运行环境分别管理密钥、数据库和 OMS 地址;审计访问需要单独权限。生产发布需要完成备份恢复演练、告警通知、密钥轮换、数据保留清理以及已确定 RTO / RPO 的验证。业务日志使用 trace 关联,不记录令牌、完整敏感正文和密钥。 | 设计领域 | 验收依据 | 必需证据 | |---|---|---| | 身份与共享服务 | AC-01~AC-08、AC-19、AC-32 | 授权结果、规则引用及业务记录 | | 确认与审批 | AC-09~AC-13、AC-23~AC-24 | 不可变版本、确认与审批审计 | | 事务与外部恢复 | AC-14~AC-17、AC-21~AC-22 | 并发事务结果、OMS 操作唯一性 | | 接管与流式输出 | AC-18、AC-20 | 控制提交时间、消息版本与事件续传 | | 记忆与消息可靠性 | AC-25~AC-28 | epoch、收据、投递及查询记录 | | 资源与质量 | AC-29~AC-35 | 按租户指标、真实用量与分类评测 | 后续工程实现按身份与数据库 → 售后服务与 OMS → 可靠投递与人工 API → Agent 与知识记忆 → 全链路验收推进。数据库迁移、OpenAPI 文件与依赖锁定随应用实现生成并验证;本文不表示已经运行这些组件。