# Retainer Agreement

> 用使用者自己的 Word 模板生成《委托代理合同》和配套《授权委托书》，支持单件与成套出件。 当用户要求"做委托合同"、"合同和授权一起出"、"新签客户"、"用我的模板出授权委托书"时使用。 支持民商事自然人/单位、刑事被告人/被害人、单/双律师及仅会见等模板类型，具体范围以用户模板为准。 首次使用（或新增文书类型）先走第 0 步初始化：agent 向使用者要本次需要的合同和授权委托书 Word， 动态提炼出要填写的位置、下划线与 tab 布局，生成模板包；没有模板包不能出件。 收费方式条款由 LLM 把口语描述润色成正式条款（含数字大写），并主动做风险审查（代理范围 / 触发条件 deadline / 后续阶段处置 / 风险代理上限 / 婚姻继承与刑事等禁风险代理红线）。

- Skill: `zj-ai-lab/retainer-agreement` (Agent Skill, multi-file: 7 files)
- Install (CLI): `npx skillmds@latest add zj-ai-lab/retainer-agreement`
- Raw SKILL.md: https://api.skillmd.com/api/skills/zj-ai-lab/retainer-agreement/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: zj-ai-lab (https://skillmd.com/u/zj-ai-lab)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/zj-ai-lab/retainer-agreement

---


# 委托合同与授权委托书（retainer-agreement）

## 定位

本 skill 是 **standalone 短任务执行型**、**模板替换型**：

| | 说明 |
|---|---|
| 内容来源 | ~80% 制式条款来自使用者的模板 + 少量每单不同的字段 |
| 输入模式 | 现场对话收集字段，不用填表 |
| 版式 | 完全继承模板（字体 / 字号 / 下划线 / tab 布局），引擎不写死任何律所的格式 |
| 模板从哪来 | 使用者自行提供本次需要的合同 / 授权委托书 Word → 初始化成各自的模板包；**缺哪份模板，就不能出哪份** |
| 配套出件 | 共用当事人等已确认信息；文书类型、律师人数、代理阶段和权限分别核对 |
| 不做什么 | 不读案件资料、不调研、不校验事实（签约时通常还没立案） |

## 何时触发

用户说出以下任一类：
- "做个委托合同" / "出一份代理合同" / "新签客户" / "签合同"
- "面谈现场出合同" / "客户来了，先出合同"
- "draft a retainer agreement"
- "合同和授权一起出" / "一套委托手续" / "用我的模板出授权委托书"

刑事辩护、常年法律顾问、非诉专项等合同：**只要使用者用第 0 步装了对应模板包就能出**；第 2 步的风险审查按模板类别取舍（见 2.6）。

## 第 0 步：模板检查与初始化（首次必走）

### 0.1 检查有没有模板包

```bash
python3 ${SKILL_ROOT}/scripts/render.py --list-templates
```

- 先定本次出哪些文件。签约默认准备“合同＋授权委托书”；使用者已说只要一份就只出那份，顾问等不需要授权的业务不强配。
- 按 `document_type`、`category`、`suitable_for` 和实际条款筛选。已有明确的案件角色 / 律师人数时直接选择；多个同类版本无法区分时再问。旧包未写 `document_type` 的，核对正文后补分类，不能只凭文件名选用。
- 只有合同包不能视为整套齐备。缺哪类模板，走 0.2 初始化；使用者本次只提供合同的，说明授权待补、按已确认范围出合同，不能宣称整套完成。
- 没有模板不能出件，不自动使用示例模板，不编造合同或授权正文。只在使用者明确试用时用虚构样本。
- 套件选择与字段边界见 [references/signing-suite.md](references/signing-suite.md)。

### 0.2 向使用者要自己的模板（自然语言，不露技术词）

agent 主动说，措辞示例：

> 首次使用，请提供你常用的委托代理合同和配套授权委托书 Word。空白模板或签过的旧稿都可以，我会与你确认每次要改的位置，再做一份示例供你核对。原文件保持不变。

**不要**对使用者说：占位符、manifest、JSON、run、XML、slug。使用者只需要给文件、回答"这里是不是每次都要改"。

### 0.3 看结构（agent 自己做）

```bash
python3 ${SKILL_ROOT}/scripts/inspect_template.py <合同.docx>
python3 ${SKILL_ROOT}/scripts/inspect_template.py <授权委托书.docx> --json
```

输出逐段编号的正文，并标注：带下划线的文字、制表符（⇥）、tab 停靠（含 leader）、首行缩进、**疑似空白下划线行**（"标签 + 制表符 + 下划线值"或 tab leader 画线）、已有 `{{KEY}}` 占位符。

agent 据此判断哪些是**每份合同都不同的内容**（变量）。判断依据优先级：带下划线的文字 > 空白下划线行 > 明显的个案信息（姓名 / 证件号 / 电话 / 地址 / 案由 / 对方 / 金额 / 日期 / 编号）。典型变量：

| 类别 | 常见变量 |
|---|---|
| 诉讼代理 | 封面日期、合同编号、委托人姓名 / 证件号 / 住址 / 电话、对方当事人、案由、承办律师、代理程序、发票类型、**收费条款（多段）** |
| 刑事辩护 | 委托人、犯罪嫌疑人 / 被告人及关系、涉嫌罪名、办案机关、委托阶段、承办律师、收费 |
| 常年顾问 | 聘请单位信息、服务期限、顾问律师、月费 / 年费与付款节点、服务范围 |
| 民事授权 | 委托人及证件 / 单位及法定代表人、律师姓名与联系方式、案由、阶段、一般代理 / 特别授权及具体权限 |
| 刑事授权 | 委托人、当事人及二者关系、身份、涉嫌罪名 / 委托事项、律师和委托阶段；不套民事权限编号 |

固定信息（本所名称 / 地址 / 账号 / 制式条款）**不是**变量。收费条款如果是逐段分期写的，把它识别成一个 **paragraphs 字段**（渲染时按使用者每次口述的期数逐段生成）。

### 0.4 用人话确认

agent 复述给使用者听，例如：

> 我准备把这几处改成每次填写的位置：委托人姓名、身份证号、住址、电话（第 16–19 行那四条下划线）、对方当事人和案由（"甲方因与 ___ ___ 纠纷"）、承办律师、代理程序、发票类型；律师费那两段我会按你每次说的分期逐段生成。有没有我漏掉的、或者其实是固定文字不该动的？

顺带问默认值："承办律师默认写谁？" "发票默认普票？" "日期默认当天？" 使用者确认或修正后再动手。

### 0.5 建模板包

按确认结果写 `map.json`（放临时目录，不给使用者看）。空白模板优先用 `inspect --json` 的 run 编号及 `build_map.py` 生成精确位置，不手数空格；同 run 的多个槽位用 `sub` 切片。格式、手填空白和预处理方式见 [references/template-mapping.md](references/template-mapping.md)。然后：

```bash
python3 ${SKILL_ROOT}/scripts/init_template.py init \
  --docx <合同.docx> --map map.json --out ${SKILL_ROOT}/templates/<slug>
```

`<slug>` 用英文短名：`<律所拼音>-<合同类型>`，如 `lanhai-minshang`、`lanhai-xingshi`。

合同与授权书分别建包，目录名与 `slug` 一致。map 中写 `document_type: contract / power_of_attorney`；`category` 标记业务类别；`suitable_for` 说明角色、人数与范围；可用 `companion_templates` 登记已安装的配套包，出件仍需核对适用性。

非必填电话等要留手填横线时用 `required: false, blank: 6`；不能给必填字段塞空格绕过校验。授权选项按本模板写 `choices`，不预设“特别授权”；收费短文本字段可设 `redline_scan: true`，避免只扫描多段收费条款。

样本值本身是通用词（如「一审」「普通发票」）、在合同固定文字里还会再出现的，给该字段加 `"leftover_ok": true`，隐私清扫就不把它当残留。

init 会先检查定位是否唯一 / 重叠，再按原文位置从后往前替换；保留各 run 格式，识别空白下划线行，处理多段锚点，并扫描样本值残留。纯空白槽自动排除残留检查，**不用** `--allow-leftover`。真实样本值残留要补位置；只有核实属于固定文字时才精确加 `leftover_ok`。`--allow-leftover` 会全局放行，只可在逐条核实后使用。

### 0.6 干跑验收（装好的标准）

用生成的 `templates/<slug>/contract.skeleton.json` 填一份示例数据（张三 / 李四 / 13800138000 / 示例路 1 号），渲染一份 .docx，**让使用者在 Word 里打开看**：要填的位置是否都在、下划线是否连续、字体版式是否和原样一致。不满意就改 `map.json` 重建（`--force`）。使用者看过点头 = 装好，进第 1 步。

### 0.7 以后再加一种合同

同一流程再建一个 `templates/<slug>/`。有多个包后，每次出件先问用哪份。在 Word 里直接改过某个 template.docx 的，跑 `init_template.py relock templates/<slug>` 重新锁定指纹。

## 第 1 步：dialog 收集字段（**必跑**）

读本次各模板包的 `manifest.json`，按 `fields` 收集，共用信息只问一次：

- 用每个字段的 `ask` 话术，口语化，**一次问 2–4 个相关的**（委托人四项一起问），不要让使用者填表。
- `required` 的必须拿到；有 `default` 的说明默认值、使用者不说就用默认。
- `hint` 是给 agent 看的换算说明（如程序代号："一审" → `1`，"一审加二审" → `1、2`，"全程" → `1、2、3`）。
- 日期类默认今天（面谈现场出合同的常态），中文大写如"二〇二六年五月二十日"，引擎按 `$today_cn` 自动生成。
- 合同编号一类由律所系统回填的字段：**留空**，不要编。
- 发票抬头一般就是委托人姓名，模板若在发票节再次引用委托人姓名，引擎自动同步。
- 授权类型、具体权限、代理阶段及期限单独确认；历史默认值不代表本次已获授权。刑事的委托人、当事人和二者关系分别收集；双律师模板必须核对第二位信息。详见套件 reference。

## 第 2 步：律师费条款润色 + 风险审查（**最关键的自定义点**）

本步适用于合同；单独出授权委托书时不追问律师费。固定金额 / 付款方式槽按模板填写，不能为套 `fee_clauses` 把整段制式文字改掉；分期方式需核对每期金额、节点与合计。金额大写和小写来自同一金额。

使用者会口语化说收费方式，如：
- "代理一审，分两次，签合同付3万，开庭前付2万"
- "执行阶段，签合同一次性付3万"
- "一审3万，二审1.5万"
- "前期固定2万 + 风险代理后续15%"

agent 必须把口语 → 正式条款数组，每个阶段一段，遵循模板原有句式；**渲染前必须跑一遍 2.5 风险审查**——口述常常隐含风险敞口，agent 不能默默套默认，必须主动追问、使用者拍板后再写进 `fee_clauses`。

### 2.1 提取结构

把口语拆成 `{阶段, 触发条件, 金额}` 三元组：

| 使用者表达 | 阶段 | 触发条件 | 金额（数字） |
|---|---|---|---|
| "签合同付3万" | 当前阶段 | "在签订本合同之日" | 30000 |
| "开庭前付2万" | 当前阶段 | "在开庭前" | 20000 |
| "二审付1.5万" | 二审 | "在收到对方上诉状或甲方确定上诉之日" | 15000 |
| "执行阶段一次性付3万" | 执行 | "在签订本合同之日" | 30000 |
| "结案后付15%风险代理" | 风险代理 | "在实现委托事项目标/效果后" | 按 % 计算 |

### 2.2 套句式

优先沿用初始化时那份样本合同里的收费句式；样本没有的用下面通用句式：

**模板 A —— 签约时一次性支付（最常见）**：
> "{阶段}阶段：在签订本合同之日，甲方向乙方支付律师代理费人民币{大写}元（¥{数字}）。"

**模板 B —— 触发条件后支付**：
> "{阶段}阶段：在{触发条件}一次性支付律师服务费{大写}元（¥{数字}）。"

**模板 C —— 风险代理（前期固定 + 后期风险）**：
> "{阶段}阶段：在签订本合同之日起三日内，甲方向乙方支付前期固定律师服务费人民币{大写}元（¥{数字}）。在实现委托事项目标/效果后支付后期风险代理律师服务费，计算方式为：{风险比例和上限}。"

### 2.3 数字大写转换

```python
from num2cn import int_to_cn     # ${SKILL_ROOT}/scripts/num2cn.py
int_to_cn(30000)   # → "叁万"
int_to_cn(15000)   # → "壹万伍仟"
int_to_cn(100000)  # → "壹拾万"
```

### 2.4 输出 fee_clauses 数组（**先过 2.5 风险审查，再落盘**）

```json
"fee_clauses": [
  "一审阶段：在签订本合同之日，甲方向乙方支付律师代理费人民币叁万元（¥30000）。",
  "二审阶段：在收到对方上诉状或甲方确定上诉之日一次性支付律师服务费壹万伍仟元（¥15000）。"
]
```

### 2.5 风险审查清单（**强制**，渲染前必跑）

**Why**：早期版本把"润色"窄化为格式润色（口语 → 正式句式 + 数字大写），结果口述里隐含的风险敞口没补，第一版 .docx 要靠律师自己看出问题再回头补——典型反模式（2026-05 一次真实签约：口述"签合同付 8000 / 受理通知书当日付 7000"被原样套模板，事后才补出"仅一审调解阶段" + "15 日内未取得受理通知书第二笔免付" + "调解失败诉讼费用另算"3 条关键条款）。

agent **必须**在 fee_clauses 准备好后、写 contract.json 之前，对照以下 5 项逐条自检；A～D 任何一项答不出来就**追问使用者**、不要默默套默认，E 项命中即按红线改写：

| 检查项 | 触发问句（使用者没明确就问） | 默认行为（使用者拒绝补充时） |
|---|---|---|
| **A. 代理范围具体到哪一阶段** | "这笔费用覆盖的是『一审全程』、还是仅『一审诉前调解』、或包含『二审 / 执行』？" | 默认套"一审阶段"并在条款里**显式写出范围边界**，例如"仅代理一审诉前调解阶段，调解不成转诉讼的代理费用另行约定。" |
| **B. 触发条件依赖外部事件 → 必须配 deadline 兜底** | "第 N 笔写的『XX 之日』（如『立案受理通知书之日』『开庭前』）属于外部触发——万一这个事件迟迟不发生或根本不发生（诉前调解通常不出受理通知书 / 立案被拖几个月），第二笔是无限期吊起还是有时限？" | 默认加一句兜底，如"自本合同签订之日起 15 日内未取得案件受理通知书的，本笔律师费甲方不再支付。" |
| **C. 后续阶段如何衔接** | "如果当前阶段（调解 / 一审）结果出来后还要继续打（调解失败转诉讼 / 一审败诉上二审 / 拿判决后申请执行），后续费用怎么算？" | 默认在最后一段加一句"后续 [二审 / 执行 / 诉讼] 阶段代理费用另行签订补充协议约定。" |
| **D. 风险代理是否设上限 / 保底** | "风险代理部分有没有按比例的上限？或者实际无回款时的保底律师费？" | 仅当口述涉及风险代理时触发；默认在模板 C 后补一句"风险代理部分最高不超过实际回款金额的 N%，且不低于人民币 X 元。"（N/X 必须问使用者拿）|
| **E. 禁止风险代理的案件类型——红线** | 案由属**婚姻家事、继承**，或模板类别为**刑事辩护、行政诉讼、国家赔偿、群体性诉讼**时："收费有没有把律师费和『离婚成功 / 拿到结果 / 判决结果』绑定——减免 / 对方反悔不收 / 判不离不收 / 取得离婚证或调解书才收 / 按所得比例提成？" | **命中即 block 改写**（不走默认套用）：依据《律师服务收费管理办法》及《关于进一步规范律师服务收费的意见》，这些案件禁止风险代理，上述表述违法。改法——付款挂程序节点（签调解协议当日 / 开庭后三日 / 立案当日），判不利结果改"递延下一程序再收"，删尽"减免 / 按结果"字样。**一般民商事案不受此限。** |

> **代码级兜底**：render.py 渲染前会对多段字段逐段跑红线词扫描（模式表 `FEE_REDLINE_PATTERNS` 在 `scripts/render.py` 顶部，可直接增删），命中打 stderr `⚠ WARN [fee-redline]`、**不拦截**渲染。它兜的是「本清单被跳过」的场景——看到 WARN 而 E 项没审过，回到本节补齐；它不替代 A–D 的追问。

**审查产出**：

- **正常情况**：5 项全过（使用者都给了明确答案 / 不适用），fee_clauses 直接落盘。
- **存在风险敞口但使用者已确认补全**：每条补出来的兜底 / 限定条款单独成段写进 fee_clauses 末尾，**不要塞进原段**——让条款层级清楚。
- **使用者来不及补 / 在赶时间**：先按原意渲染 V1，但在交付时**显式标红**："⚠ 风险审查发现 N 项未确认（A/B/C/D/E），建议 Word 打开后补 / 在 V2 一起谈：[逐条列出问题]。" 不要假装审查通过了。（**E 项命中属合规红线，不适用"赶时间先渲染"——必须当场改写，不能留到 V2。**）

**反模式（不要做的）**：

- ❌ 默默套"一审阶段"不问代理范围
- ❌ 把"XX 之日"写进条款却不问 deadline 兜底
- ❌ 把"调解阶段"渲染出来但不问后续诉讼如何衔接
- ❌ 风险代理写比例不问上限和保底
- ❌ 婚姻 / 继承 / 刑事案把对客户的"对方反悔不收 / 判不离不收"温情承诺原样搬进收费条款（＝疑似风险代理、违法；须翻译成"程序节点付款 + 判不利递延再收"）

### 2.6 按模板类别取舍

manifest 的 `category`：`litigation`（民商事诉讼 / 仲裁）A–E 全套；`criminal` 刑事——E 项直接命中（刑事案件禁止风险代理），A/C 按阶段（侦查 / 审查起诉 / 审判）问；`advisory` 常年顾问——问服务期限、付款节点、超出范围事项如何计费，A–D 不适用；`other` 由 agent 酌情。

## 第 3 步：写 contract.json

字段名 = manifest 每个 field 的 `json`（模板包自带 `contract.skeleton.json` 可直接复制填写）。以一份民商事诉讼代理模板为例：

```json
{
  "template": "<slug>",
  "year": 2026,
  "contract_num": "",
  "cover_date_cn": "",
  "client_name": "...",
  "client_id": "...",
  "client_address": "...",
  "client_phone": "...",
  "opponent": "...",
  "case_matter": "...",
  "lawyer": "",
  "proc_codes": "1、2",
  "invoice_type": "1",
  "fee_clauses": ["...", "..."],
  "output_path": "<落盘路径>/民商事委托代理合同_{客户}_V1.docx"
}
```

- 空字符串 = 用 manifest 默认值（日期 → 今天；律师 → 默认承办律师；编号 → 留空）。
- `template` 只有多包时必填；单包自动选用。
- `output_path` 可选：不给则按 manifest `output_name` 落在当前目录；命名习惯 `<合同名>_{client_name}_V1.docx`，改稿递增 V2 / V3。

成套出件用 `suite.json` 的 `shared` 共用数据＋`documents` 各自数据与文件名；不同字段名用 manifest 字段 `shared` 绑定同一语义。关系描述、代理权限等不能按相似名称盲目共用。完整示例见 [references/signing-suite.md](references/signing-suite.md)。

## 第 4 步：渲染 .docx

```bash
python3 ${SKILL_ROOT}/scripts/render.py contract.json output.docx            # 单包
python3 ${SKILL_ROOT}/scripts/render.py contract.json output.docx --template <slug>   # 多包
python3 ${SKILL_ROOT}/scripts/render_suite.py suite.json --outdir <本次输出目录>        # 合同＋授权
```

套件脚本先校验全部文件再落盘；缺模板、必填为空、共享值冲突或输出重名均停止，已有文件不覆盖。

stderr 可能出现：
- `⚠ WARN [fee-redline]`：收费条款命中红线词（2.5-E 的代码级兜底）——婚姻 / 继承 / 刑事必须回 2.5-E 改写后重渲；一般民商事核对 D 项上限 / 保底后可继续交付。
- `⚠ WARN [template-drift]`：template.docx 与 manifest 指纹不符——使用者自己在 Word 改过模板就 `init_template.py relock`；否则查模板是否被换。
- `✗ 必填字段为空`（exit 4）：回第 1 步补问。
- `✗ … 没有任何模板包`（exit 3）：回第 0 步。

## 第 4.5 步：格式自检

逐份核对：字段全部替换、原“标签：”仍在、下划线与手填槽保留；单律师没有悬空顿号或误填第二律师。模板原有的第二律师手填栏是否保留按用户确认处理，不擅自删版式。套件比对委托人、当事人、律师、阶段和权限范围，逐份确认适用的角色与业务类型；附页已内置的风险告知书不重复出。发现差异回到模板映射或字段确认，不直接改制式授权条款。

全角标点检查（合同正文中文语境）：
- 所有标点必须全角："" '' ， 。 ： ； ！ ？ 《》 、
- 例外（保留半角）：身份证号 / 电话 / URL / 金额数字 / 英文专有名词

```bash
python3 -c "
from docx import Document
import re
d = Document('output.docx')
for i, p in enumerate(d.paragraphs):
    m = re.search(r'[一-龥][,.:;?!\"'()]', p.text)
    if m:
        print(f'[{i}] {m.group()!r} in: {p.text[:80]}')
"
```

## 第 5 步：交付

- 列出本次全部 .docx 路径及待手填位置；缺模板的配套文件明确标待补。风险审查有未确认项的按 2.5「审查产出」列出。

## 模板包与 manifest

```
templates/<slug>/
├── template.docx            占位符版模板（{{KEY}}）
├── manifest.json            字段清单 / 提问话术 / 默认值 / 渲染方式 / 模板指纹
└── contract.skeleton.json   contract.json 骨架
```

manifest 字段说明见 `scripts/render.py` 顶部注释；目录约定与隐私说明见 `templates/README.md`。渲染规则：

- `kind: text`：`{{KEY}}` 所在 run 就地替换，继承字体 / 字号 / 下划线；
- 空白下划线行：由结构判定（占位符独占带下划线的 run 且前一个 run 是制表符），整行重建为单 run `[tab][值][tab]` 连续下划线，短值居中、长值左对齐自动缩字号；首行缩进 / 右侧 tab / 字号从该段自身读取；
- `kind: paragraphs`：整段锚点，按数组逐段克隆插入；`underline: amounts` 给中文大写金额与 ¥ 数字加下划线。

**不要**手改 template.docx 里的占位符文字；改版式去 Word 改后 `relock`；改字段 / 话术 / 默认值直接改 manifest.json。

## 隐私与发布边界

- 初始化只把样本里的当事人信息替换成占位符；样本原件不复制进模板包；manifest 不保存样本值；init 隐私清扫拦截残留。
- 模板包含本所固定信息（所名 / 地址 / 账号），属律所资料——**不要把模板包提交到公开仓库**；示例数据一律脱敏（张三 / 李四 / 110101… / 13800138000 / 示例路 1 号）。
- 共创者提供的合同、授权书、配置包与固定默认值均不入公开仓；只吸收通用代码和流程。测试用代码即时生成虚构样本，不携带模板副本。`ask` / `hint` / `notes` / `default` 也要检查个案残留。
- 脚本在本机处理 Word；所用 AI 助手可能把读取的内容发送给其模型服务，不能承诺整条链路“不上传”。初始化清扫辅助检查已映射样本值与疑似号码，不是全文件隐私审计；旧稿还应核对批注、修订和文档属性。

## 不在范围

- 不读案件资料、不调研、不校验事实
- 不自动生成合同编号（律所系统回填）
- 不在页眉页脚里放变量（init 暂只处理正文与表格）
- 不做合同条款的实体审查（只审收费条款的风险敞口与红线）

## 依赖

- Python 3.10+，`python-docx >= 1.2`（`pip install python-docx`）

## 版本管理

- 改 SKILL.md 或 scripts/* → bump version + 写 CHANGELOG.md
- SemVer：MAJOR = manifest / contract.json schema 变、工作流 step 重排；MINOR = 新字段类型、新审查项、新脚本能力；PATCH = 措辞、bug 修

