系列说明:本篇是「DeerFlow-By-CC × Cruxible 清结算全链路实战」系列的下篇,纯操作向:8 步在本机跑出一张清结算复杂图谱,再过一遍从 Demo 到生产还差的 10 件事。上篇讲了为什么清结算场景需要给 Agent 配一个确定性图谱,以及 17 类实体、25 类关系的本体是怎么设计出来的,建议先读一遍再来看这篇。

以下所有命令、路径、代码片段都已在本机验证通过。源码仓库位置:


一、完整实操手册:8 步跑通清结算复杂图谱 POC

alt text

Step 1:启动 DeerFlow-By-CC 全栈(7 容器)

cd /Users/qian/Documents/workspace/deer-flow-by-cc/docker
DEER_FLOW_ROOT=/Users/qian/Documents/workspace/deer-flow-by-cc \
  docker compose --env-file ../.env -p deer-flow-dev -f docker-compose-dev.yaml up -d --build

打开 http://localhost:2026 验证 UI 能访问。

Step 2:启动 Cruxible daemon(8100)

cd /Users/qian/Documents/workspace/cruxible
uv sync --all-extras
uv run cruxible server start --port 8100 --state-dir .poc/cruxible_server_state

Step 3:启动 Cruxible MCP(SSE,8123)——DeerFlow-By-CC 通过 SSE 连工具

cd /Users/qian/Documents/workspace/cruxible
FASTMCP_HOST=0.0.0.0 FASTMCP_PORT=8123 \
  CRUXIBLE_MODE=admin CRUXIBLE_MCP_TRANSPORT=sse \
  CRUXIBLE_SERVER_URL=http://127.0.0.1:8100 \
  uv run cruxible-mcp-http

这个入口脚本见 server_http.py,它支持 stdio / sse / streamable-http 三模式,这里选 SSE。

Step 4:确认 DeerFlow-By-CC 的 extensions_config.json 指向 SSE(否则 tools 加载不到)

关键在 deerflow 的 extensions_config.json,把 stdio 版 cruxible 禁用,启用 SSE:

"mcpServers": {
  "cruxible":     { "enabled": false, "type": "stdio", "...": "..." },
  "cruxible_sse": {
    "enabled": true, "type": "sse",
    "url": "http://host.docker.internal:8123/sse",
    "description": "Cruxible MCP over SSE (connect to host cruxible-mcp-http)"
  }
}

同时关闭 tool_search.enabled(否则 MCP 工具可能不直接暴露给模型),见 config.yaml

Step 5:用清结算本体注册一个 daemon instance(你会拿到 instance_id)

cd /Users/qian/Documents/workspace/cruxible
curl -fsS -X POST http://127.0.0.1:8100/api/v1/instances \
  -H 'Content-Type: application/json' \
  -d "$(python3 -c 'import json; print(json.dumps({\"root_dir\":\"/Users/qian/Documents/workspace/cruxible/.poc/cruxible_server_state/instances/inst_settlement_poc\",\"config_yaml\":open(\".poc/settlement/settlement_poc_config.yaml\",\"r\",encoding=\"utf-8\").read()}))')"

你会拿到类似:

{"instance_id":"inst_d9634d5c1e624449","status":"ready","warnings":[]}

把这个 instance_id 记录下来。Cruxible 内部用这个 ID 做实例句柄;最终用户不应该直接看到它(体验优化见下一步)。

Step 5.5(强烈推荐):配置 CRUXIBLE_DEFAULT_INSTANCE_ID——把默认实例绑定从 prompt 级升级到环境变量级

alt text

把默认实例绑定从「SOUL.md prompt 级写死」升级为「环境变量 + MCP 层统一解析」:Operator 只配一次 env,所有实例作用域工具(cruxible_query / cruxible_list_queries / cruxible_workflow_* / cruxible_batch_direct_write / cruxible_schema / cruxible_stats / cruxible_inspect_* 等)都自动使用默认实例,Agent 只有在用户明确要求「新建 / 切换实例」时才显式传 instance_id。

操作方法(Cruxible MCP 启动命令替换 Step 3 的命令,或直接补充 env):

cd /Users/qian/Documents/workspace/cruxible
FASTMCP_HOST=0.0.0.0 FASTMCP_PORT=8123 \
  CRUXIBLE_MODE=admin CRUXIBLE_MCP_TRANSPORT=sse \
  CRUXIBLE_SERVER_URL=http://127.0.0.1:8100 \
  CRUXIBLE_DEFAULT_INSTANCE_ID=inst_d9634d5c1e624449 \
  uv run cruxible-mcp-http

实现原理(对应源码链路):

  1. 新增统一解析器:cruxible_core.mcp.default_instance.resolve_default_instance_id(explicit_instance_id)——显式非空则直接用,否则读 CRUXIBLE_DEFAULT_INSTANCE_ID 兜底,env 空则抛 ConfigError,提示 operator 如何配置(见 default_instance.py)。
  2. MCP tools 全部把第一个参数 instance_id 的类型改为 str | None = None,并在 docstring 末尾声明「未提供时使用 CRUXIBLE_DEFAULT_INSTANCE_ID」(见 tools.py)。
  3. MCP handlers 所有实例作用域 handler 第一行执行 resolved, _used_default = resolve_default_instance_id(instance_id),并把后续调用的 instance_id 替换成 resolved(见 handlers.py)。
  4. cruxible_server_info 返回值同步新增 default_instance_id 字段(daemon HTTP 层、service 层、runtime 层、contracts 四处),Agent 可自动感知默认实例并在 UI/日志中提示(见 server.pytypes.pyapi.pycontracts.py)。

对应 SOUL 侧简化:只保留两条原则,不再把 inst_xxx 写死在 prompt 中(见 SOUL.md):

默认实例选择:
- 所有 cruxible_* 工具调用默认**不写 instance_id**,由 MCP 层读取 CRUXIBLE_DEFAULT_INSTANCE_ID 注入;
- 仅当用户明确要求「新建实例 / 切换到另一个实例 / 跨实例对比查询」时,才向工具显式传入 instance_id。

验证方法(见 Step 8):

# 1. 不传 instance_id,检查 server_info 暴露默认实例
curl -fsS -X POST http://127.0.0.1:8123/sse -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"cruxible_server_info","arguments":{}}}'
# 返回值中应包含 "default_instance_id": "inst_d9634d5c1e624449"

# 2. cruxible_list_queries 不传 instance_id,成功返回查询列表(自动走默认)
curl -fsS -X POST http://127.0.0.1:8123/sse -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"cruxible_list_queries","arguments":{}}}'
# 应返回 settlement_batches / batch_to_merchants / diff_top20 等 10+ 个命名查询。

这就是「实例 ID 藏在系统里,Agent 写 prompt 只专注业务问题」的工程化形态。

Step 6:在 DeerFlow-By-CC 里生成清结算 POC spec(你只做这一步)

进入 DeerFlow-By-CC UI → Agent 画廊 → 选 cruxible sub-agent → New Chat。把下面提示词粘进去:

你要生成一个用于"清结算/对账/报表/审批/审计"的 POC 输入 JSON。要求:
1) JSON 必须包在 ```json ... ``` 代码块里;
2) 顶层必须包含:poc="settlement_reconciliation_v1";
3) 必须包含 spec 字段:{seed:int, scale:"large", counts:{days, merchants, channels, orders, ledger_entries_per_order, disputes, audit_events}, currencies:[...], countries:[...]};
4) 不要直接生成全量订单/分录明细(会太大),只输出 spec。

复制这个新对话的 thread_id(URL 里 /chats/<thread_id> 的那一段)。

Step 7:一键跑 DeerFlow-By-CC thread → Cruxible 落图(含 receipts)

脚本:poc_deerflow_settlement_to_cruxible.py

cd /Users/qian/Documents/workspace/cruxible
uv run python scripts/poc_deerflow_settlement_to_cruxible.py \
  --deerflow-base-url http://localhost:2026 \
  --thread-id <Step6拿到的thread_id> \
  --daemon-url http://127.0.0.1:8100 \
  --instance-id <Step5拿到的instance_id> \
  --progress

脚本内部会:调用 DeerFlow-By-CC /api/threads/{id}/state 拿到 spec;生成全量复杂数据集(Merchant/Channel/Account/FeeRule/FXRate/PaymentOrder/Transfer/LedgerEntry/SettlementBatch/ReconcileRun/ReconcileLine/Dispute/Report/Approval/AuditEvent + 所有关系);分批(每批 512 实体 + 每批 400 关系)调用 cruxible_batch_direct_write 写入 daemon;最后输出 dataset_path(完整数据集 JSON,可做离线分析/回归)和 receipt_entity_count / receipt_edge_count / receipt_ids

重要安全说明(生产教训):用户第一次 spec 可能写 orders=2,000,000。脚本里用 _CAP_COUNTS 做安全截断,把订单压在数千级,避免把本机跑死。这种「上游输入不可信」的闸门,企业里必须有。

落图后验证:Step 7 跑完之后,直接打开 Cruxible-app 的 Views 列表和 settlement_batches 查询页,下面两张图是跑完后的真实 UI(已带 Receipt ID):

图 2-1 · 真实 UI 证据:Cruxible Views / Named Queries 列表 — 落图后的命名查询总览(队列视图 + 参数化视图)

图注 · Named Queries 视图:落图后,Workflow 把 settlement_batches(列表)、batch_to_merchants(批次反查商户)、diff_top20(差异排序 Top20)等 3+ 个参数化查询全部注册了。每个查询都有必填参数输入框和 Run 按钮,Run 后会自动生成 Receipt 并在页面右下角挂出来。

图 2-2 · 真实 UI 证据:Cruxible Query Result — <code>settlement_batches</code> 视图返回的 2,520 条清结算批次(带 Receipt:RCP-f4cf853ad220)

图注 · Settlement batches 查询结果:真实批次号 b_c_000_20260602_cny / b_c_000_20260602_eur 等,列按「Settlement batch id → Channel id → Cycle date → Currency → Total amount → Status」顺序一一对应上篇存在层 Level 3 的实体定义;页面右下角 RCP-f4cf853ad220 是这次查询的 Receipt ID,可以事后 cruxible_get_receipt 逐条审计。

Step 8:可视化 + 对话排障

cruxible-app 复杂图谱可视化

用 Docker 启动 cruxible-app:

cd /Users/qian/Documents/workspace/cruxible-app
docker run --rm -it -p 5174:5174 \
  -e VITE_CRUXIBLE_DAEMON_URL=http://host.docker.internal:8100 \
  -e VITE_CRUXIBLE_FIXTURES=0 \
  -e VITE_CRUXIBLE_INSTANCE_ID=inst_d9634d5c1e624449 \
  -v "$PWD":/app -w /app node:20-bullseye \
  bash -lc "npm ci && npm run dev -- --host 0.0.0.0 --port 5174"

打开 http://localhost:5174/i/inst_d9634d5c1e624449/graph(5.6 万节点 / 12.8 万边的复杂图,建议先缩小到 settlement_batch 级别再展开邻域)。

下面两张是 Step 8 跑完的真实 UI 证据:左(State Graph)是大图版,左侧筛选器按类型过滤后可以只看 SettlementBatch → ReconcileRun → ReconcileLine 的对账链;右(Entity Browse · SettlementBatch)是主链实体的明细行级别浏览,每一行是一个 SettlementBatch,点击 ID 可以看该批次的所有关联边、所有 Receipts、所有历史 Snapshots。

图 2-3 · 真实 UI 证据:Cruxible State Graph(5.6 万节点 / 12.8 万边,cosmos 渲染)

图注 · State Graph:点击左侧 Settlement batch 筛选按钮,可以把 2520 个批次单独展开;再点 1 个批次 node,右侧详情抽屉会列出 batch_for_channel / batch_reconciled_by_run / report_for_batch / thread_produced_batch 四条主链关系——这就是上篇因果链 A/B/C/D 的可点击版本。

图 2-4 · 真实 UI 证据:Cruxible Entity Browse — SettlementBatch 实体明细浏览(分页 + Filter + 全列排序)

图注 · Entity Browse:2520 条 SettlementBatch 实体,支持 Filter、分页、按任意列排序;列头「Id / Title / Status / Channel id / Currency / Cycle date / Generated at / Paid at / Total amount」9 列与上篇 Level 3 存在层实体的属性定义一一对应——这是 Cruxible 的 Schema 强约束落地到 UI 的直接证据:Schema 里没写的列,UI 绝不会出现。

在 DeerFlow-By-CC 里直接问(不用提 instance_id)

选中 cruxible sub-agent,直接问下面 6 个问题(按从浅到深排序):

  1. 看大盘:“列出最近的 settlement batches 前 10 条,按 settlement_date 倒序,返回 receipt_id。”
  2. 选批次看商户:“拿 b_c_000_20260605_eur 这个 batch,列出 merchant 维度:订单数、GMV 总金额、差异单数,并返回 receipt_id。”
  3. 差异归因 Top N:“同一个 batch 里,按 diff_reason 分类统计差异条数和总 diff_amount,把 fee_mismatch 和 fx_mismatch 单独列出来。”
  4. 单笔订单全链路追溯(graph layout):“挑 1 条 diff_amount 最大的 reconcile_line,按 batch_to_line_to_dispute 这条路径做 graph layout,展示完整批次→run→line→order→dispute 链路。”
  5. 报表审批:“这个 batch 生成了哪些 report?每个 report 的 approval 结果是什么?把 rejected 的 comment 归类。”
  6. 合规审计:“围绕 order_id = <挑一个>,把所有相关 audit_event 拉出来,按时间生成一条审计时间线,并给出这条时间线的 receipt_id。”

二、企业化改造清单:从 Demo 到生产的 10 个必做项

alt text

POC 能跑,不代表能上线。下面 10 件事,缺任何一件在金融/支付行业都进不了生产。

1. 多实例与多租户:instance_id 要被抽象掉

最终用户不应该知道 instance_id。企业落地时至少要做两层抽象:

抽象层 含义 典型实现
业务别名(Ontology/Project ID) 用户说「清结算 POC 图谱」→ 系统解析到 instance_id 别名表 + 环境变量 + agent SOUL 默认值
租户隔离 租户 A 的清结算图谱和租户 B 的清结算图谱物理隔离 每个租户独立 daemon state-dir / 独立 schema / Postgres schema

2. 权限落地:ADMIN/GRAPH_WRITE/GOVERNED_WRITE/READ_ONLY 分环境配置

开发环境用 CRUXIBLE_MODE=admin;测试环境用 CRUXIBLE_MODE=graph_write(允许自动 apply workflow,但不让变更 active config);UAT/生产用 CRUXIBLE_MODE=governed_write(Agent 只能提 feedback,不能直接写图,图谱变更走审批流);只读大屏/BI 用 CRUXIBLE_MODE=read_only

工具级权限表见 permissions.py:L83-L110,建议做一张审计表,把每次工具调用的 actor / time / mode / receipt_id 都存下来。

3. 持久化升级:SQLite → Postgres / MySQL

POC 用 SQLite 很方便,但生产建议把 state.db 的所有表(receipts, traces, feedback, groups, proposals, snapshots, artifacts)迁移到 Postgres;图谱实体/关系本身如果要做 10 亿级,建议后端抽象层再拆一层(InstanceProtocol 已预留,见 instance_protocol.py)。

4. 高可用:daemon 集群化 + 健康检查

Cruxible daemon 目前是单进程;企业化做法是至少 2 个 daemon 实例,front by nginx;健康检查接口 GET /api/v1/server/info(返回 permission_mode / instance_count / head_snapshot);写请求和长事务走 leader,读请求走 replica(配合 Postgres 主从)。

5. 与企业 IdP 集成:OIDC/OAuth + RBAC

DeerFlow-By-CC 侧接企业 OAuth2;Cruxible daemon 侧启用 CRUXIBLE_SERVER_AUTH=true + CRUXIBLE_RUNTIME_BOOTSTRAP_SECRET(见 config.py:L130-L143),再把 OAuth scopes 映射到 PermissionMode:cruxible:read → READ_ONLY,cruxible:governed_write → GOVERNED_WRITE,cruxible:graph_write → GRAPH_WRITE,cruxible:admin → ADMIN。

6. 版本化:本体(config)+ workflow + lock file 全 Git 化

Cruxible 的 lock 文件(cruxible.lock.yaml)是 workflow 的 hash。本体 config 必须 Git 管理;每次本体变更走 PR + 小版本号;每次 workflow 变更重新 cruxible lock_workflow 并提交 lock;CI 跑 cruxible test_workflow 作为回归(版本号管理规则见 AGENTS.md 的 Versioning 章节)。

7. 监控与告警:receipt 失败率 + 图谱一致性评分

不要只监控「daemon 是否活着」,要监控 4 类业务指标:

  1. 工具层:cruxible_query P95 latency / 4xx rate / 5xx rate;
  2. 治理层:每小时 feedback 数量;pending review 的 group 数量;rejected approval rate;
  3. 图谱质量层cruxible_evaluate 的 6 项检查(见 evaluate.py:L37-L42):orphan_entity(孤立项)、coverage_gap(实体类型在图中缺失)、constraint_violation(约束违规)、unreviewed_co_member(未审核成员)、quality_check_failed(质量规则失败)、governed_support_relationship(治理关系评估);
  4. 可复现层:workflow run 的 apply_digest 与 expected_apply_digest 不匹配率。

8. 幂等 & 回滚:snapshot 是你的后悔药

Cruxible 有 cruxible_state_create_overlayhead_snapshot_idexpected_head_snapshot_id 三件套。任何 canonical workflow apply 之前,先在 CI 跑 preview(run mode=canonical)拿到 apply_digest;只有 apply_digest 一致才允许正式 apply。生产上出问题时,直接回滚到 origin_snapshot_id

9. PII 合规:敏感字段要加密 + 审计

DeerFlow-By-CC thread state 里通常有用户聊天内容(PII)。Cruxible 图谱里像 Account.bank_nameAuditEvent.payload 都可能带 PII。PII 字段统一用 envelope encryption(KMS);读取级别做字段级脱敏(compact / standard / full 三种 profile 已经预留,配合 RBAC);cruxible_mcp_read_profile 默认为 compact(见 handlers.py:L109-L136),只返回身份卡 + 治理标记,不把 payload 全量暴露给 agent context。

10. SRE/观测:所有 tool call 都要带 trace_id

Cruxible 已经有 trace_id(provider 执行痕迹)。企业化时建议给 DeerFlow-By-CC 的每次 chat 注入 correlation_id;所有 cruxible_* tool call 透传这个 id;把 receipts / traces / audit_events 统一入 OpenSearch / Datadog。

图 3 · 真实 UI 证据:Cruxible Overview — 企业级治理仪表盘(实例级统计、命名查询队列、快照历史、Receipt 治理 4 条主线一览)

图注 · 企业治理 Dashboard:Cruxible-app Overview 页,对应上面 10 项企业化清单的落地成果可视化:左侧实体类型数量对应清单 1(多实例/多租户数据密度观测);State by status + Active incidents 对应清单 7(监控告警);Snapshots 区域对应清单 8(幂等 + 快照回滚);Payment orders / Settlement batches 两个队列视图对应清单 3(持久化升级:队列读写延迟直接来自 SQLite / Postgres 的真实 IO);右下角 Receipt ID 链贯穿清单 6(GitOps 版本化)——每条队列查询都能拉回完整的 Receipt + Snapshot 链。


三、6 大死穴逐一对照解法

上篇讲了 Agent 工程的 6 大死穴,这里做一个收尾对照,方便回顾:

死穴 解法(DeerFlow-By-CC + Cruxible) 关键实现
语义对齐缺失 用 Cruxible Config 声明 entity_types / relationships / primary_keys / descriptions settlement_poc_config.yaml
推理不可证明 每次 query 都有 receipt;可复现遍历路径和快照 tools.py:L238-L237 / handlers.py
治理缺失 4 层累积权限 + feedback + groups + approvals permissions.py:L61-L99
上下文爆炸 Agent 只出 spec;实际生成/计算/批量写入交给 workflow/script;paginated query Step 6 + Step 7 拆分
与已有系统割裂 4 种集成模式覆盖 CDC/Webhook/ETL/对话 上篇第五章
可复现性不足 snapshot + lock file + canonical workflow workflow run → apply 二阶段提交

alt text


四、给读者的 3 个作业(今天就能上手)

  1. 复现本 POC:照着第一章 8 步,本机跑通一张至少 1 万节点的清结算图谱;
  2. 做一个差异归因的 named query:在 config 里加一个 batch_diff_top_reasons(按 diff_reason 聚合 count 和 sum(diff_amount)),在 DeerFlow-By-CC 里问出来,并把 receipt 导出成审计工作底稿;
  3. 把默认实例绑定升级到更真实的体验:把 SOUL 里硬编码的 instance_id,改成「Cruxible 启动时读环境变量 CRUXIBLE_DEFAULT_INSTANCE_ID=inst_xxx」,实现代码级注入而不是 prompt 级注入。

五、结语:Agent 的第二曲线,在「敢被审计」

很多团队把大量精力花在「怎么让 Agent 回答更像人」上。但金融行业的真实问题是:只要它说的话不能被证明、不能被追责、不能回归复现,业务就不敢用它。

DeerFlow-By-CC × Cruxible 这套组合,给了一个具体的工程蓝图:自然语言留给 DeerFlow-By-CC;事实、证据、规则、治理交给 Cruxible;两者之间用 MCP 这层标准协议,搭出一个既好用又敢用的 AI 工作台。

清结算只是第一个落地行业,这套打法稍加改造,同样适用于保险理赔(保单 → 报案 → 核赔 → 打款 → 反欺诈)、供应链金融(采购单 → 发票 → 运单 → 仓单 → 保理)、监管合规(产品准入 → 尽调 → 审批 → 存续期 → 报送)。这些行业的共同点是:错一笔,就是真金白银甚至合规处罚。对它们来说,确定性从来不是可选项,而是入场券。

参考资料: