卓卓安Claw项目方案库
展示首页/方案库/技术决策
技术决策

ADR-002:及锋 Agent 与卓安Claw 的深度集成

约 16 分钟·卓安Claw · 2026.11
本页目录
  1. 1. 问题
  2. 2. 及锋现状(源码核对)
  3. 3. 目标架构
  4. 3.1 为什么 V1 用网页端扩展,而不是桌面端
  5. 3.2 案件工作台怎么放进网页端
  6. 4. 案件上下文如何进入 Agent
  7. 4.1 前端
  8. 4.2 后端
  9. 4.3 提示词
  10. 5. 工具与写回
  11. 5.1 工具清单
  12. 5.2 写回流程
  13. 6. 权限、数据分级与审计
  14. 6.1 身份
  15. 6.2 权限
  16. 6.3 数据分级
  17. 6.4 审计
  18. 7. 原型与正式版的分界
  19. 7.1 本轮原型已做(zaclaw)
  20. 7.2 正式版第一步(网页端,建议 3 人 × 1 周)
  21. 7.3 不在本期
  22. 8. 风险与应对
  23. 9. 结论
  • 状态:已采纳(V1 范围修订)
  • 日期:2026-11-09
  • 决策人:项目组
  • 关联:ADR-001 技术选型、docs/requirements/卓安Claw-及锋多用户改造可行性报告-v0.1.md

2026-11-09 范围修订(V1)

11/27 演示和 V1 先不做 Electron 桌面端,统一走及锋网页端(channel/web,默认 http://localhost:9899/),用浏览器上大屏。desktop/ 目录冻结,不构建、不签名、不打安装包。

下文涉及 desktop/、ChatPage、ChatView 的内容只保留为 V2 桌面端参考;V1 以 §3.1、§3.2、§4.1 的网页端方案为准。


1. 问题

上一版原型把 Agent 做成了案件右侧的“三个按钮 + 预生成草稿”面板:

  • 没有对话历史,不能连续追问;
  • 没有输入框,不能问“为什么”“换成另一种说法”;
  • 没有真实流式步骤,工具调用是假的;
  • 没有把案件上下文真正传给 Agent。

这不是“及锋 + 卓安Claw 深度结合”,只是一个 Agent 展示位。

本 ADR 明确:卓安Claw 的 Agent 必须是及锋 Agent 本体,案件工作台只是它的“工作现场”,不是另写一个聊天机器人。


2. 及锋现状(源码核对)

层 文件(V1 网页端) 事实
会话页 channel/web/templates/views/chat.html、channel/web/static/js/chat/*.js 网页端已有完整会话:历史、流式、停止、重生成、附件
会话状态 channel/web/static/js/chat/state.js activeStreams、消息列表、历史加载
发送与 SSE channel/web/static/js/chat/send.js POST /message;new EventSource('/stream?request_id=')
路由 channel/web/api/chat.py、channel/web/web_channel.py MessageHandler / StreamHandler
后端 channel/web/core/channel.py WebChannel.post_message();SSE 事件名 delta/tool_start/tool_end/...
Agent 执行 agent/chat/service.py ChatService.run() 把 Agent 事件转成 CHAT chunk;_build_context() 目前只放 session_id/receiver
系统提示 agent/prompt/builder.py build_agent_system_prompt() 负责人格、工具、技能、记忆、知识、工作区
现有案管 jifeng-features/case_manager/、channel/web/api/jifeng_extras.py /api/casemgr 已接网页端,但和 Agent 没有数据往来
桌面端(V2 参考) desktop/src/renderer/... 本版冻结,不构建、不签名、不打安装包

关键结论:

  1. 不需要新写聊天前端。 及锋网页端的 chat/*.js 已经是成品,卓安要做的是“把案件工作台放进网页端,并让它知道当前案件”。
  2. 现有 /message 没有 case_id。 这是网页端必须补的第一条链路。
  3. WebChannel 的 Context 与 ChatService._build_context() 是两条上下文路径。 只改其中一条会出现“前端带了案件、Agent 没收到”的假集成。
  4. 案管已经在后端。 卓安案件主线应做成网页端视图,直接调 /api/casemgr,不再套 iframe + 独立 SQLite。
  5. 桌面端冻结。 V1 不改 desktop/,避免 Electron 构建、签名、安装包拖慢 11/27 演示。

3. 目标架构

┌──────────────────── 浏览器(1920×1080 大屏,无安装) ────────────────────┐
│  及锋网页端:http://localhost:9899/                                       │
│  ├─ /zhuoan?case=ZA-2026-0318   卓安案件工作台                           │
│  │   ├─ 左:12 节点诊疗主线 / 清单 / 文档 / 留痕                          │
│  │   └─ 右:及锋网页端会话(复用 chat/*.js,不另写聊天)                   │
│  └─ 现有 /、/settings、/knowledge、/skills 等                             │
├────────────────────────────────────────────────────────────────────────────┤
│  channel/web:templates/views + static/js/chat                            │
│  ├─ 发送:send.js → POST /message { session_id, message, case_id }         │
│  └─ 接收:EventSource /stream?request_id=...(事件协议不变)               │
├────────────────────────────────────────────────────────────────────────────┤
│  WebChannel.post_message()                                                 │
│  ├─ 读取 case_id,写入 context["case_id"]                                  │
│  └─ CaseContextService 做权限、数据范围、C 类裁剪                           │
├────────────────────────────────────────────────────────────────────────────┤
│  ChatService.run() → AgentStreamExecutor                                   │
│  ├─ CASE_CONTEXT 注入系统提示(案件、阶段、清单、文档索引、角色)           │
│  └─ 工具:case.get_context / case.list_checklist / doc.search_local ...     │
├────────────────────────────────────────────────────────────────────────────┤
│  卓安私有云:PostgreSQL(案件/权限/审计)+ OSS(案卷)+ 本地检索索引        │
│  C 类文件:只在私有云/本机检索,不把全文发给外部模型                        │
└────────────────────────────────────────────────────────────────────────────┘

3.1 为什么 V1 用网页端扩展,而不是桌面端

  • 11/27 在浏览器上大屏演示,零安装、零签名、零升级链路,现场风险最低。
  • channel/web 已经有完整的 /message、/stream、会话历史、附件和工具事件,不需要重写聊天。
  • 卓安只增加网页端视图、案件上下文和权限,不动 desktop/,上游升级冲突最小。
  • 桌面端保留到 V2;届时再把同一套网页端视图包进 Electron,而不是现在并行维护两套。

3.2 案件工作台怎么放进网页端

V1 不新开前端工程,直接在现有 console 里加一个视图:

channel/web/
├─ templates/views/zhuoan.html      # 案件工作台视图(左主线 + 右会话容器)
├─ static/js/views/zhuoan.js        # 病例主线、清单、文档、留痕交互
├─ static/js/chat/send.js           # 复用;请求体增加 case_id
├─ static/js/chat/state.js          # 复用;保存 currentCaseId
└─ web_channel.py                   # 增加 /zhuoan 路由

实现要点:

  • 路由 /zhuoan 复用现有 console shell,不复制整套 chat.html;
  • 仅在 /zhuoan 视图显示案件侧栏和“当前案件”上下文条;
  • 会话仍是现有 chat/*.js,不复制、不重写;
  • currentCaseId 从 URL 参数或案件列表选择写入 state.js,send.js 每次发送都带上;
  • 旧案管数据通过 /api/casemgr 读取,逐步替换 iframe 入口。

这样既保留及锋网页端的成熟会话,又让 Agent 在案件现场工作。


4. 案件上下文如何进入 Agent

4.1 前端

V1 改网页端 channel/web/static/js/chat/send.js。正常发送和重发两处 body 都加:

const body = {
  session_id: sessionId,
  message: text,
  stream: true,
  timestamp: timestamp.toISOString(),
  lang: currentLang,
  case_id: window.currentCaseId || undefined
};

currentCaseId 由 /zhuoan 视图写入(建议放 chat/state.js 的全局状态),从 URL 参数或案件列表选择得到。请求体:

{
  "session_id": "s-...",
  "message": "基于案卷生成会见提纲",
  "stream": true,
  "case_id": "ZA-2026-0318"
}

会话仍然按 session_id 隔离,案件只是消息的附加上下文,不改变及锋的会话模型。

V2 桌面端对应 desktop/src/renderer/src/api/client.ts 的 sendMessage 加 caseId,本版不做。

4.2 后端

channel/web/web_channel.py 的 post_message():

case_id = (json_data.get("case_id") or "").strip()
...
context["case_id"] = case_id

ChatService.run() 增加 case_id 参数(或从 Context 读取),并把它带到 _build_context():

ctx["case_id"] = case_id

然后由 CaseContextService 统一解析,不要让 Agent 直接拿 case_id 去查库:

case_ctx = case_context_service.resolve(
    case_id=case_id,
    user_id=context["user_id"],
    role=context["role"],
    branch=context["branch"],
)

CaseContextService.resolve() 必须做四件事:

  1. 校验用户能否看这个案件(角色 + 数据范围 + 案件团队 + 分所);
  2. 按数据分级裁剪:C 类文档只返回本地索引/摘要,不返回全文;
  3. 返回结构化上下文:案件基本信息、当前阶段、下一节点、必做项、未完成项、文档索引、团队成员;
  4. 写一条 agent.context.read 审计(谁、何时、为哪个案件、调用了什么)。

4.3 提示词

在 agent/prompt/builder.py 增加一个 CASE_CONTEXT 段,放在“工作区”之后、“项目上下文文件”之前:

## 当前案件上下文(服务端注入,勿向用户泄露内部字段)
- 案件编号:ZA-2026-0318
- 案件名称:张某涉嫌合同诈骗案
- 当前阶段:治疗/办案(第 8/12 节点)
- 下一节点:三级复核/会诊
- 数据分级:B 类(C 类文档仅本地)
- 当前角色:承办律师(案件团队成员)
- 未完成必做项:取保候审申请(进行中)、辩护意见初稿(进行中)、开庭预案(未开始)
- 可用文档索引:起诉意见书、阅卷笔录、取保候审申请(仅索引,不含全文)

约束:

  • 这段由服务端生成,前端不能伪造;
  • 不含真实客户姓名、身份证号、银行账号等敏感字段;需要引用时用案件内代号;
  • C 类内容只出现“索引/摘要”,不出现全文;
  • 提示词里明确“Agent 不审批、不签字、不付款,写入需律师确认”。

5. 工具与写回

5.1 工具清单

工具 类型 作用 是否需要律师确认
case.get_context 读 取案件阶段、团队、清单摘要 否
case.list_checklist 读 取必做项与状态 否
doc.search_local 读 本地 BM25/向量检索,返回 page#chunk 引用 否
doc.read_summary 读 读文档摘要/索引;C 类不返回全文 否
case.add_timeline 写 追加案程 是
doc.create_draft 写 生成草稿并挂到案件文档区 是
checklist.update 写 标记清单完成/不适用 是
case.advance_stage 写 推进 12 节点 是,且只允许承办/管理者
audit.log 写 记录 Agent 调用与写回 否(系统自动)

5.2 写回流程

Agent 生成草稿
  → 前端显示“插入案件”按钮
  → 律师点击确认
  → 前端调用 POST /api/cases/:id/agent-writeback
  → 后端校验角色/数据范围/案件状态
  → 写 case_timeline + case_document + audit_log(同一事务)
  → 返回新版本号
  → 前端刷新案程/留痕

禁止:

  • Agent 自己调用 case.advance_stage;
  • Agent 直接把草稿写入正式文档区而不经确认;
  • 用服务超级账号绕过用户权限。

6. 权限、数据分级与审计

6.1 身份

  • 企业微信组织架构 → 分所/部门/角色;
  • 每个律师一个及锋账号;Agent 继承当前用户 token,不继承服务账号;
  • V1 可用企业微信 OIDC + Keycloak;正式版接卓安统一身份。

6.2 权限

沿用现有 packages/domain/src/permissions.ts 的口径,服务端必须再实现一遍:

  • 角色:客服、客户经理、谈案律师、承办律师、管理者(正式版加财务、运营);
  • 数据范围:本人 / 本部门 / 本分所 / 全所 / 案件团队;
  • 硬边界:客服不看案卷;客户经理不看真实报价;承办不看财务成本;客户只看公开内容。

6.3 数据分级

级别 示例 Agent 通道
A 公开宣传、知识文章 可云端
B 一般案件信息、程序性文书 脱敏后可云端
C 案卷、当事人隐私、证据全文 只本地检索/模板/规则校验,不发给外部模型
D 财务、人事、密钥 Agent 不可读

6.4 审计

每次 Agent 调用至少记录:

{
  "actor": "赵楠",
  "role": "承办律师",
  "case_id": "ZA-2026-0318",
  "action": "agent.chat",
  "model": "deepseek-chat",
  "data_class": "B",
  "tools": ["doc.search_local", "doc.create_draft"],
  "writeback": ["case.add_timeline"],
  "request_id": "req-...",
  "at": "2026-11-27T10:52:00+08:00"
}

审计只追加,不覆盖;可按案件、人、时间、动作检索。


7. 原型与正式版的分界

7.1 本轮原型已做(zaclaw)

  • AgentChat.tsx:网页会话 UI(历史、输入、流式、停止、重生成、工具步骤、引用、写回);
  • agent-transport.ts:按及锋 SSE 事件名驱动的演示传输层;
  • 每条消息携带 AgentCaseContext(案件、阶段、角色、分所、数据分级、未完成项);
  • “插入案件”会写案程 + 审计,并自动切到“留痕”页;
  • 客服角色无 agent:run,会话区显示权限锁定。

zaclaw 原型继续作为视觉与交互参考;V1 的真实落点是 zhuoan-claw/channel/web,不把 React 原型直接当产品前端。

7.2 正式版第一步(网页端,建议 3 人 × 1 周)

步骤 负责人 产出
1 A channel/web 增加 /zhuoan 视图:左 12 节点主线,右复用现有会话;不复制聊天 JS
2 C chat/send.js 增加 case_id;WebChannel.post_message() 透传;CaseContextService + CASE_CONTEXT 提示词段;只读工具 case.get_context / case.list_checklist
3 B 案件上下文条、清单/文档/留痕联动、写回确认;审计页展示 Agent 调用
4 全员 浏览器打开 http://localhost:9899/zhuoan?case=ZA-2026-0318 走通:问案件 → 出会见提纲 → 插入案件 → 留痕可见

验收:

  • 同一个 session 内连续追问,Agent 记得上一轮;
  • 问“这个阶段缺什么”,回答能列出本案未完成必做项;
  • 引用能回到具体文档/法条;
  • 插入草稿后,案程和审计各多一条,阶段不变;
  • 客服账号进不去案件页,也调不动 Agent;
  • C 类文档的全文不出现在任何外部模型请求里;
  • 全程在浏览器完成,不需要安装 Electron 客户端。

7.3 不在本期

  • 不做 Electron 桌面端、不构建安装包、不做代码签名;
  • 不重写及锋 Agent 内核;
  • 不做独立的卓安聊天前端;
  • 不把旧案管 iframe 直接换成正式案管(先用 /zhuoan 视图承接演示);
  • 不做 GPU 私有化部署(V1 用外部模型 API + 脱敏 + 审计)。

8. 风险与应对

风险 应对
新增 /zhuoan 视图影响现有 console 只加视图和路由,不动 /、/settings、/knowledge;回归现有 console
case_id 只在前端传递,后端不认 以“后端返回的案件上下文”作为唯一事实源;前端字段仅用于展示
两套上下文路径漏传 在 WebChannel 和 ChatService 各加一条集成测试,断言 case_id 到达 prompt
C 类文件被外部模型看到 服务端按 data_class 裁剪;请求体审计;本地检索单独通道
上游升级冲突 卓安代码放 channel/web 的 templates/views/zhuoan.html、static/js/views/zhuoan.js;核心只保留 case_id 一个最小改动

9. 结论

卓安Claw 不是“及锋 + 一个案件 CRM”,而是“及锋 Agent 在案件现场工作”。

  • 会话必须是及锋的会话;
  • 案件上下文必须由服务端注入,前端不能伪造;
  • 写回必须经律师确认并留审计;
  • 权限和数据分级必须在服务端再实现一遍。

本轮原型先把“会话 + 案件上下文 + 写回”跑通;V1 按 7.2 在及锋网页端接真实 /message + /stream,不再增加模拟 Agent 按钮,也不做桌面端。