# Foreign Trade Assistant — 项目需求文档

> 基于用户实际业务需求整理。最后更新：2026-05-11。

---

## ⚠️ 核心约束：全面兼容 Windows 与 macOS

> **本项目必须在 Windows 和 macOS 上均可正常运行。任何功能设计、代码实现、路径处理都必须同时考虑两个平台。**

| 约束项 | 要求 |
|--------|------|
| **路径处理** | 统一使用 `pathlib.Path`，禁止硬编码 `/` 或 `\` |
| **文件名命名** | 统一小写 + 连字符（slug），禁止使用 Windows 保留字符 `<>:"/\|?*` |
| **目录深度** | ≤ 3 层，确保不超过 Windows MAX_PATH（260 字符）限制 |
| **大小写** | Windows 不区分大小写，文件名统一小写避免冲突 |
| **换行符** | 读写文本文件时使用 `utf-8` + `newline=''`（Python 自动处理 `\r\n`） |
| **Shell 命令** | 不在代码中直接拼接 shell 命令；Hermes 在 Windows 上捆绑 MinGit |
| **环境变量** | 使用 `TRADE_HOME`（macOS: `~/.trade/`，Windows: `%LOCALAPPDATA%\trade\`） |
| **安装方式** | macOS 用 `curl ... | bash`（同 Hermes），Windows 用 PowerShell 脚本 |

**Hermes 上游的 Windows 支持状态**（参照 2026-05 Hermes README）：
- Windows native 为 **Early Beta**，已有 PowerShell 一键安装脚本
- 安装路径：`%LOCALAPPDATA%\hermes\`
- 捆绑 MinGit（便携 Git Bash）用于 shell 命令执行
- WSL2 路径与 Linux 相同（`~/.hermes/`），是"战斗测试最充分"的 Windows 方案

**本项目对 Windows 的定位**：
- 目标：与 macOS 同等的完整功能支持
- 最低要求：Windows 10 及以上
- 终端：PowerShell 5.1+ 或 Hermes 捆绑的 MinGit Bash
- 文件系统：NTFS（默认）或 ReFS

---

## 一、项目定位

**外贸公司的 AI 销售助手**。不是简单的文档问答工具，而是覆盖「引流 → 转化」全链路的智能销售系统。

传统外贸公司面临两个核心问题：
1. **引流（找客户）**：怎么找到更多潜在客户？
2. **转化（拿订单）**：怎么把潜在客户变成真实订单？

Foreign Trade Assistant 通过训练 Hermes Agent 学习顶级销售员的思维模式和业务技能，帮助外贸业务员在引流和转化两个环节提效。

**核心架构**：Agent Loop — LLM 自主决定读什么文件、搜什么信息、生成什么内容，多轮迭代直到任务完成。

---

## ⚠️ 核心约束：代码架构（高内聚低耦合）

> 业务逻辑必须拆分。单一脚本 / 模块不能过长。模块内部高内聚，模块之间低耦合。
> 新增于 2026-05-12。

### 规则总览

|| 规则 | 说明 |
|------|------|
| **单一职责** | 每个模块（`.py` 文件）只负责一件事 |
| **文件行数上限** | 单个 `.py` 文件 ≤ 500 行；超过必须拆分 |
| **禁止上帝模块** | 不得出现 `utils.py`、`helpers.py` 堆积无关联函数 |
| **层级调用禁止逆向** | 上层模块可调用下层，下层模块不得引用上层 |
| **依赖方向等于调用方向** | A 模块 import B 模块，则 B 不能循环 import A |

### 模块分层架构

```
trade/                          # 业务层（最上层，调用所有下层）
├── api.py                      # HTTP 路由（≤ 800 行），仅做请求解析 + 响应组装
├── helpers.py                  # 跨模块共享的薄胶水函数（解析配置、构建 prompt）
├── prompt.py                    # System prompt 模板（纯数据）
│
├── company.py                   # 公司实体（单一职责：company CRUD）
├── library.py                   # 文档库实体（单一职责：library CRUD）
├── customer.py                  # 客户实体（单一职责：customer CRUD）
├── chat_memory.py               # 对话记忆（单一职责：conversation CRUD）
│
└── database.py                  # 数据访问层（单一职责：DB 连接 + schema + 迁移）
```

**分层说明**：

| 层级 | 模块 | 职责 | 可调用 |
|------|------|------|--------|
| L1（入口） | `api.py` | HTTP 解析、响应、SSE 流 | L2 |
| L2（业务） | `company`/`library`/`customer`/`chat_memory` | 业务实体 CRUD | L3 |
| L3（数据） | `database.py` | DB 连接、schema、迁移 | 无（纯工具） |
| L4（数据） | `helpers.py` / `prompt.py` | 配置解析、prompt 模板 | L3（仅 helpers） |

### 拆分触发条件

当一个模块满足以下任一条件时，**必须立即拆分**：

```
1. 总行数 > 500 行
2. 职责种类 > 1 种（不含纯数据结构）
3. 存在与当前模块无关的 import 链
4. 测试时需要 mock 超过 3 个外部依赖
```

### 拆分操作规范

**问题模块** → **拆分步骤**：

```
1. 识别该模块承担的所有职责
2. 按职责拆分为独立 .py 文件（单一职责）
3. 新模块放置在同一层或下一层（依赖方向向下）
4. 原模块降级为薄转发层（仅 import + re-export）
5. 确保无循环依赖
```

**示例**：假设 `chat_memory.py` 膨胀到 600 行，同时处理 conversation CRUD 和 hindsight 调用：

```
chat_memory.py (600 行)
    ├── chat_memory.py          # conversation CRUD（降级为薄层，≤ 100 行）
    └── memory.py                # Hindsight 客户端封装（新增 L2 模块）
```

### 禁止模式

```
❌ utils.py（万能工具箱，积累无关联函数）
❌ helpers.py 堆积 > 200 行
❌ api.py 出现业务逻辑（DB 操作、实体判断）
❌ L3 模块（L2 的下层）import L2 模块
❌ 跨层调用链：api.py → database.py → api.py（循环）
```

### 代码注释规范

> 代码中必须包含充分的中文说明文字，使阅读者无需阅读实现细节即可理解意图和逻辑。
> 新增于 2026-05-12。

**所有函数必须有 docstring**：

```python
def get_library(library_id: int, company_id: int) -> dict | None:
    """根据 ID 获取指定公司的文档库。

    Args:
        library_id: 文档库主键 ID
        company_id: 公司主键 ID（用于数据隔离校验）

    Returns:
        文档库字典（含 id/name/root_path/description/created_at）；
        不存在或不属于该公司时返回 None。

    Raises:
        不会抛异常，所有错误情况均返回 None。
    """
```

**复杂逻辑必须分行注释**：

```python
# ❌ 差：无注释
result = [x for x in items if x.get("active") and x.get("company_id") == cid]

# ✅ 好：分行注释
active_items = [x for x in items if x.get("active")]      # Step 1: 筛选激活状态
company_items = [x for x in active_items                   # Step 2: 按公司隔离
                 if x.get("company_id") == cid]
```

**每个 if/分支必须有说明**：

```python
if not agent_identity:
    # 无公司身份配置时，使用通用系统提示词（降级策略）
    system_parts = [TRADE_SYSTEM_PROMPT]
else:
    # 注入公司身份：公司名称、产品范围、销售风格
    system_parts = [TRADE_SYSTEM_PROMPT, "", "## 公司身份配置", agent_identity]
```

**每章节代码块之间用注释分隔**：

```python
# =====================================================================
# 第一部分：健康检查（Provider 检查 → 模型配置检查）
# =====================================================================

# =====================================================================
# 第二部分：构建查询（公司身份 → prompt 组装 → 库上下文注入）
# =====================================================================
```

**注释覆盖率要求**：

|| 代码类型 | 最低要求 |
|---------|---------|
| 函数 docstring | 全部（含 private 函数） |
| if/分支 | 每个分支均有说明 |
| 循环 | 复杂循环有行内注释 |
| 异常处理 | 说明为何 try/except 及捕获后的处理策略 |
| API 路由 | 行末说明业务含义（如 `# 公司 ID 必填，否则无法隔离数据`） |
| 关键业务逻辑 | 注释说明决策依据和业务规则 |

**CI 检查**（可选，用 `radon` 或 ` lizard`）：

```bash
# 检查注释密度（comment ratio），低于 15% 报警
radon cc -a trade/ -e "migrations|__pycache__"
```

### 验证机制

每次提交前确认：

```bash
# 检查行数
find trade/ -name "*.py" -exec wc -l {} \; | awk '$1 > 500 {print}'

# 检查循环依赖（meld / pydeps）
python -c "import trade.api; import trade.company; print('OK')"
```

---



> **Foreign Trade Assistant 必须从 `chefroger/hermes-agent` 安装 Hermes，不得从其他源安装。**

### 版本锁定策略

| 策略 | 说明 |
|------|------|
| **安装源** | `git+https://github.com/chefroger/hermes-agent.git` （唯一合法源） |
| **版本声明** | `pyproject.toml` 中 pin 到具体的 git tag 或 commit hash |
| **启动检查** | `server.py` 启动时校验 Hermes 版本号，不匹配则拒绝启动 |
| **升级协议** | Hermes 升级后必须先通过兼容性检查（见下方），再更新 Trade 的版本 pin |

### 安装前预检（pre_install_check）

由于 `pip install trade` 不会自动安装 hermes-agent（依赖声明只是声明，不触发安装顺序），
Trade 提供 `pre_install_check.py`，在安装 trade **之前**主动检测 hermes-agent 状态：

```
安装 trade 之前
    │
    └─ python pre_install_check.py
           │
           ├─ hermes-agent 未安装 → exit 1 + 打印 chefroger fork 安装说明
           ├─ 已安装但来源错误（NousResearch） → exit 2 + 卸载重装说明
           ├─ 版本过低（< 0.12.0） → exit 2 + 升级说明
           └─ 版本兼容（>= 0.12.0，chefroger fork） → exit 0 → 继续安装 trade
```

**退出码**：

| 退出码 | 含义 |
|--------|------|
| 0 | 兼容，继续 `pip install trade` |
| 1 | hermes-agent 未安装，请先安装 |
| 2 | hermes-agent 版本不兼容或来源错误 |

**安装 chefroger fork 的 Hermes**：

```bash
# 官方一键安装（使用 chefroger fork 而非 NousResearch）
curl -fsSL \
  https://raw.githubusercontent.com/chefroger/hermes-agent/main/scripts/install.sh \
  | bash

# 或手动克隆
git clone --branch main \
  https://github.com/chefroger/hermes-agent.git \
  ~/.hermes/hermes-agent
cd ~/.hermes/hermes-agent
uv pip install -e .   # 或 pip install -e .
```

**预检脚本位置**：项目根目录 `pre_install_check.py`（343 行，stdlib-only，无外部依赖）。

### 前置软件依赖矩阵

> 以下为 hermes-agent 在各操作系统上运行所需的全部前置软件。
> **必需** = 核心功能无此不可运行；**可选** = 缺少时对应功能降级，但不阻塞运行。

#### Windows（PowerShell）

| 优先级 | 软件 | 版本要求 | 安装方式 | 说明 |
|--------|------|----------|----------|------|
| **必需** | Python | ≥ 3.11 | Hermes 安装器自动通过 uv 安装 | 运行时核心 |
| **必需** | Git（含 Bash） | 任意 | Hermes 安装器自动下载 PortableGit | terminal tool 和 agent-browser 必需 |
| **必需** | uv | 最新 | Hermes 安装器自动安装 | Python 包管理器 |
| **可选** | Node.js | ≥ 22 LTS | `winget install OpenJS.NodeJS.LTS` | Hermes 浏览器工具需要 |
| **可选** | ripgrep | 任意 | `winget install BurntSushi.ripgrep.MSVC` | 加快 Hermse 文件搜索 |
| **可选** | ffmpeg | 任意 | `winget install Gyan.FFmpeg` | TTS 语音消息需要 |

> **注意**：Windows 上 Git 是**必需**而非可选。Hermes 的 terminal tool 和 agent-browser 依赖 Git Bash 环境。
> Hermes 安装器（`install.ps1`）会自动下载 PortableGit（隔离安装，无需管理员权限）。

#### macOS

| 优先级 | 软件 | 版本要求 | 安装方式 | 说明 |
|--------|------|----------|----------|------|
| **必需** | Xcode Command Line Tools | 任意 | `xcode-select --install` | 提供 git, make, clang |
| **可选** | Homebrew | 最新 | `/bin/bash -c "$(curl -fsSL ...)"` | 简化后续包管理，非必需 |
| **可选** | Python | ≥ 3.11 | Hermes 安装器通过 uv 管理 | 自动处理 |
| **可选** | Node.js | ≥ 22 LTS | `brew install node@22` | 浏览器工具需要 |
| **可选** | ripgrep | 任意 | `brew install ripgrep` | 加快文件搜索 |
| **可选** | ffmpeg | 任意 | `brew install ffmpeg` | TTS 语音消息需要 |
| **可选** | Playwright Chromium | 任意 | `npx playwright install --with-deps chromium` | 浏览器自动化需要 |

#### Linux（Debian/Ubuntu）

| 优先级 | 软件 | 安装命令 |
|--------|------|----------|
| **必需** | curl, git, ca-certificates | `sudo apt install curl git ca-certificates` |
| **必需** | build-essential（C 编译工具） | `sudo apt install build-essential python3-dev libffi-dev` |
| **可选** | ripgrep | `sudo apt install ripgrep` |
| **可选** | ffmpeg | `sudo apt install ffmpeg` |
| **可选** | Node.js ≥ 22 | `curl -fsSL https://deb.nodesource.com/setup_22.x \| sudo -E bash - && sudo apt install nodejs` |
| **可选** | Playwright Chromium | `npx playwright install --with-deps chromium` |

#### Linux（Fedora/RHEL/CentOS）

| 优先级 | 软件 | 安装命令 |
|--------|------|----------|
| **必需** | curl, git | `sudo dnf install curl git` |
| **必需** | gcc, gcc-c++, make, python3-devel, libffi-devel | `sudo dnf install gcc gcc-c++ make python3-devel libffi-devel` |
| **可选** | ripgrep | `sudo dnf install ripgrep` |
| **可选** | ffmpeg | `sudo dnf install ffmpeg` |

#### Termux（Android）

| 优先级 | 软件 | 安装命令 |
|--------|------|----------|
| **必需** | clang, rust, make, pkg-config, libffi, openssl, ca-certificates, curl, git | `pkg install clang rust make pkg-config libffi openssl ca-certificates curl git` |

#### 前置软件一键安装脚本

| 脚本 | 平台 | 路径 |
|------|------|------|
| `install_prereqs.sh` | macOS / Linux / Termux | `scripts/install_prereqs.sh` |
| `install_prereqs.ps1` | Windows (PowerShell) | `scripts/install_prereqs.ps1` |

使用方法：

```bash
# macOS / Linux
chmod +x scripts/install_prereqs.sh
./scripts/install_prereqs.sh

# Windows (PowerShell)
powershell -ExecutionPolicy Bypass -File scripts/install_prereqs.ps1
```

> 两个脚本仅安装系统依赖，**不包含 Hermes Agent 本身**。Hermes 由官方 `install.sh` / `install.ps1` 安装。

### 版本检查流程

```
Trade 启动 (python server.py)
    │
    ├─ 1. 读取 hermes_cli.__version__ → "0.12.0"
    ├─ 2. 对比 Trade 声明的兼容版本范围
    │      ├─ 匹配 → 正常启动
    │      └─ 不匹配 → 打印错误并退出：
    │           "Hermes version 0.13.0 is not compatible.
    │            Foreign Trade Assistant requires hermes-agent>=0.12.0,<0.13.0.
    │            Please run: pip install 'hermes-agent>=0.12.0,<0.13.0'"
    └─ 3. 启动日志记录 Hermes 版本号
```

### 升级兼容性检查清单

当 Hermes 发布新版本时，必须在 Trade 侧执行以下检查后才能更新版本 pin：

1. [ ] `from hermes_agent import AIAgent` 导入成功
2. [ ] `AIAgent(quiet_mode=True, max_iterations=90, ...)` 初始化成功
3. [ ] `agent.chat("Hello")` 返回字符串
4. [ ] `from hermes_cli.config import load_config` 正常
5. [ ] `from hermes_cli.auth import PROVIDER_REGISTRY` 正常
6. [ ] `MemoryProvider` ABC 接口无变化（cognee plugin 的方法签名全部匹配）
7. [ ] Trade 的 `/api/trade/chat` 和 `/api/trade/chat/stream` 端点正常响应
8. [ ] `trade_chat.html` 前端正常加载

### 版本号记录

每次 Hermes 升级后，在 Trade 仓库的 `COMPATIBILITY.md` 文件中记录：

```markdown
| Hermes 版本 | 兼容状态 | 测试日期 | 备注 |
|------------|---------|---------|------|
| 0.12.0     | ✅ 兼容  | 2026-05-11 | 当前锁定版本 |
| 0.13.0     | ⏳ 待测试 | -       |      |
```

---

## 二、目标用户与运行环境

| 维度 | 说明 |
|------|------|
| 用户 | 外贸公司老板 / 业务员，非技术背景 |
| 硬件 | 16 GB 办公机（Windows / macOS） |
| 并发 | 无并发需求 |
| 隐私 | 文档本地分析，API Key 用户自备 |
| 平台 | macOS / Linux / Windows（native + WSL2）|

### 2.1 跨平台路径设计

参考 Hermes Agent 的 `HERMES_HOME` 模式，Trade 使用 `TRADE_HOME` 环境变量控制数据目录。

| 平台 | Hermes 目录 | Trade 目录 |
|------|-----------|-----------|
| macOS | `~/.hermes/` | `~/.trade/` |
| Linux / WSL2 | `~/.hermes/` | `~/.trade/` |
| Windows native | `%LOCALAPPDATA%\hermes\` | `%LOCALAPPDATA%\trade\` |

**Windows 兼容措施**：
- 路径操作统一使用 `pathlib.Path`，不硬编码分隔符
- 目录名 / 文件名统一小写 + 连字符（slug 格式），避免大小写敏感问题
- 目录层级 ≤ 3 层，不超过 Windows MAX_PATH 限制
- 复用 Hermes 在 Windows 上捆绑的 MinGit 执行 shell 命令

---

## 三、多公司架构（Multi-Tenancy）

> 每个公司有独立的 AI 身份、文档库、客户和对话记录，数据完全隔离。
> 新增于 2026-05-11。

### 架构概述

```
companies ──────────── trade_companies
    │                        │
    │ 1:N                    │ 1:1 (每个公司对应一条 Trade 配置记录)
    ▼                        ▼
libraries ──────────── conversations
    │
    ▼
customers
```

**数据隔离**：所有 API 端点和数据库查询均通过 `company_id` 过滤，跨公司数据完全隔离。

### 数据库变更

|| 表 | 变更 | 说明 |
|----|------|------|
|| `companies` | 新增 | 公司基本信息（name, slug, contact, is_active） |
|| `trade_companies` | 新增 | Trade 专属配置（data_dir, agent_identity_md） |
|| `libraries` | +company_id | FK → companies(id)，级联删除 |
|| `customers` | +company_id | FK → companies(id)，级联删除 |
|| `conversations` | +company_id | FK → companies(id)，级联删除 |

**备用列（Spare Columns）**：所有表均预留 3 个 TEXT 类型备用列（`extra1`/`extra2`/`extra3`），默认 `'{}'`，用于存储 JSON 结构的扩展字段，避免未来 schema 变更需要 ALTER TABLE。所有 6 张表共计 18 个备用列。

|| 表 | extra1 | extra2 | extra3 |
|----|------|--------|--------|--------|
|| `companies` | `{"industry":"","country":""}` | `{"employee_count":"","annual_revenue":""}` | 预留给未来扩展 |
|| `trade_companies` | `{"max_iterations":90,"temperature":0.7}` | `{"model":"","provider":""}` | 预留给未来扩展 |
|| `libraries` | `{"scan_depth":3,"file_count":0,"last_scan":""}` | `{"indexed":false,"index_version":1}` | 预留给未来扩展 |
|| `customers` | `{"country":"","website":"","linkedin_url":""}` | `{"customer_type":"","tier":"","source":""}` | 预留给未来扩展 |
|| `customer_libraries` | `{"relevance_score":0.0,"notes":""}` | 预留给未来扩展 | 预留给未来扩展 |
|| `conversations` | `{"tokens_used":0,"model":"","duration_ms":0}` | `{"rating":null,"feedback":""}` | `{"tools_used":[],"iterations":0}` |

幂等补充机制：`_add_spare_columns(conn)` 在 `init_db()` 和 `_migrate_from_v0()` 中各调用一次，使用 `ALTER TABLE ADD COLUMN`（列已存在时 SQLite 静默忽略），支持安全重复执行。

### v0 迁移

首次启动时检测旧 schema（无 `company_id` 列），自动执行迁移：
1. 创建 `companies` 和 `trade_companies` 表
2. 创建默认公司「我的公司」(slug=default)
3. 为现有 `libraries`/`customers`/`conversations` 添加 `company_id` 列，设为 1
4. 新增索引：`idx_libraries_company`、`idx_customers_company`、`idx_conversations_company`

### Agent 身份注入

每个公司可以配置自己的 AI 身份（`agent-identity.md` 内容或 `agent_identity_md` 字段），Chat 时注入系统提示词：

```
TRADE_SYSTEM_PROMPT

## 公司身份配置     ← 从 company agent_identity_md 注入
你是一家专业外贸公司的销售助手...
```

**优先级**：`trade_companies.agent_identity_md`（数据库字段） > `~/.trade/{slug}/agent-identity.md`（文件） > 空（使用通用 prompt）

### API 路由变更

所有数据端点（libraries/customers/conversations）均需 `X-Company-ID` Header。

| 端点 | 变更 |
|------|------|
| `GET /companies` | 新增 |
| `POST /companies` | 新增 |
| `GET/PUT/DELETE /companies/{id}` | 新增 |
| `GET/PUT /companies/{id}/agent-identity` | 新增 |
| `GET /libraries` | + X-Company-ID，改为 `list_by_company()` |
| `POST /libraries` | + company_id |
| `GET /customers` | + X-Company-ID，改为 `list_by_company()` |
| `POST /customers` | + company_id |
| `GET/POST /conversations` | + X-Company-ID |
| `POST /chat` | + X-Company-ID required | `HERMES_YOLO_MODE=true` 自动设置，无需用户审批 |
| `POST /chat/stream` | + X-Company-ID required | 同上 |

### 前端多公司 UI

- 侧边栏顶部：公司选择下拉框 + 添加公司按钮
- 无公司时显示引导页，不允许发送消息
- 切换公司时自动清空当前对话，加载新公司的库/客户列表
- `sessionStorage['trade_company_id']` 保存当前公司 ID（刷新不丢失）

### 文件结构

```
~/.trade/                         # TRADE_HOME（运行时数据）
├── default/                      # slug=default 公司数据目录
│   ├── company-profile.md
│   ├── agent-identity.md
│   ├── products.md
│   ├── clients/
│   └── libraries/
└── another-company/              # 第二家公司
    ├── company-profile.md
    └── ...

.trade-template/                  # 仓库中展示模板（安装时复制到 ~/.trade/）
```

---

## 三、核心业务功能

### 3.1 引流 — 找客户

#### 3.1.1 B2B 平台诊断与优化

用户提供阿里国际站 / 中国制造网 / 独立站的产品链接，Agent 诊断平台店铺并给出改进方案：
- 分析产品标题、关键词、描述的质量和覆盖度
- 检查产品图片、视频是否符合平台最佳实践
- 对比同行 Top 店铺，指出差距和优化方向
- 输出可直接执行的产品发布 / 修改清单

**输入**：平台店铺链接 或 产品链接
**输出**：诊断报告 + 改进方案（标题优化、关键词建议、描述模板、图片要求）

#### 3.1.2 社媒内容策略与素材生成

用户提供同行社媒账号链接（Facebook / Instagram / TikTok / YouTube），Agent 学习同行内容策略后，结合本公司产品生成社媒发布方案：
- 分析同行的内容类型、发布频率、互动数据、标签策略
- 生成适用于本公司产品的社媒内容日历（周 / 月计划）
- 提供可直接发布的具体帖文（文案 + 图片建议 + 标签）

**输入**：同行社媒链接（可多个）+ 本公司产品资料
**输出**：社媒发布方案 + 内容日历 + 具体帖文（可直接复制粘贴发布）

#### 3.1.3 领英营销方案

用户提供本公司产品资料，Agent 结合领英 B2B 开发方法，生成完整的领英营销方案：
- **客户画像**：基于产品特征定义目标客户（职位、行业、地区、公司规模）
- **个人账号设置**：头像、背景图、标题、About 部分的内容模板
- **公司主页设置**：公司介绍、产品展示、员工邀请策略
- **年度营销方案**：包含计划时间表和具体执行内容，可直接复制粘贴使用
- **内容素材库**：行业洞察帖、产品价值帖、客户案例帖的模板库

**输入**：本公司产品册 / 参数表 + 行业资料
**输出**：客户画像 + 账号设置模板 + 公司主页内容 + 年度营销方案（含计划表）

#### 3.1.4 海关数据 / 广交会数据挖掘

用户上传海关数据（进出口记录）或广交会参展商数据，Agent 自动筛选：
- 从数据中提取本行业的目标客户（采购商 / 进口商）
- 分析客户采购规律（频次、数量、品类、季节）
- 按优先级排序输出目标客户列表
- 给出每个客户的开发建议（切入点、推荐产品、预期订单量）

**输入**：海关数据文件（CSV / Excel）+ 本公司产品范围
**输出**：本行业目标客户列表 + 开发优先级 + 每个客户的开发策略

---

### 3.2 转化 — 拿订单

#### 3.2.1 AI 高级销售员

Agent 通过学习以下资料，训练为具备高级外贸销售员思维模式和业务技能的 AI：

**训练资料**：
1. 高级销售员的思维方法论

**能力要求**：
- 理解 B2B 销售心理学和决策链路
- 掌握外贸全流程：询盘 → 报价 → 谈判 → 成交 → 跟单
- 能根据不同客户类型调整沟通策略（价格敏感型 / 品质导向型 / 关系型）
- 会处理常见客户异议（价格太高、已有供应商、暂时不需要等）

#### 3.2.2 客户分析与开发信

用户将领英或其他渠道找到的潜在客户信息粘贴给 Agent，Agent 分析客户并生成开发信：

**分析维度**：
- **客户公司**：规模、主营产品、市场定位、供应链特征
- **联系人**：职位、决策权限、可能的采购关注点
- **匹配度**：与我司产品的契合点、切入角度

**输出内容**：
- 客户分析报告（公司能力 + 联系人画像 + 切入建议）
- 定制化开发信 / 领英 InMail（可直接复制粘贴发送）
- 跟进消息序列（Day 1 / Day 3 / Day 7 / Day 14）
- 首次沟通的 talking points 和常见问题预案

**输入**：领英客户链接 或 客户信息文本（公司名 + 联系人 + 职位）
**输出**：客户分析报告 + 开发信 / 消息 + 跟进计划

---

### 3.3 文档库管理与产品问答

#### 3.3.1 文档库管理

- 创建文档库 → 关联本地目录
- 每个客户可关联多个文档库（多对多）
- 支持 16 种文件格式：

| 类别 | 格式 | 处理方式 |
|------|------|---------|
| 文字型 PDF | `.pdf` | PyMuPDF 提取文字；< 500 字则走 OCR |
| 扫描型 PDF | `.pdf` | Tesseract OCR |
| 现代 Word | `.docx` | python-docx 提取段落 + 表格 |
| 旧版 Word | `.doc` | LibreOffice → `.docx` → python-docx |
| 现代 Excel | `.xlsx` | openpyxl 读取单元格 |
| 旧版 Excel | `.xls` | xlrd 读取 |
| Excel 模板 | `.xlt` | LibreOffice → `.xlsx` → openpyxl |
| CSV | `.csv` | Python csv 模块 |
| Numbers | `.numbers` | zipfile 解析内部 XML |
| 现代 PPT | `.pptx` | python-pptx 提取文字 |
| 旧版 PPT | `.ppt` | LibreOffice → `.pptx` → python-pptx |
| HTML | `.html` | BeautifulSoup 提取正文 |
| Markdown / 纯文本 | `.md` / `.txt` | 原生读取 |
| 图片 | `.jpg` / `.png` / `.jpeg` | Tesseract OCR |

#### 3.3.2 产品智能问答

```
用户自然语言提问
  → Agent 列出目录文件
  → Agent 判断哪些与问题相关
  → Agent 逐个读取文件（原生理解 PDF / Excel / Word / 图片 OCR）
  → 信息不够？继续读更多
  → 交叉比对，综合所有信息
  → 生成答案 + 标注来源文件
```

- Agent 自主决定读什么、读多少、何时停，不硬截断
- 回答须包含精确数据 + 单位 + 来源文件标注
- 最多 90 轮 tool-calling 迭代，单次最长 10 分钟

---

### 3.4 新公司营销方案 Onboarding

新公司想用 Foreign Trade Assistant 部署完整营销打法，需要准备以下资料：

| 序号 | 必需资料 | 说明 |
|------|---------|------|
| 1 | **公司介绍** | 自身的核心优势。基础版可让 Agent 帮忙优化润色 |
| 2 | **产品介绍** | 产品册、产品参数表、行业产品范围清单 |
| 3 | **同行公司** | 同行公司名 / 链接（用于竞争分析和差异化定位） |
| 4 | **领英账号** | 公司主页 + 业务员个人账号（有则提供） |

Agent 在收到以上资料后，可一次性输出：公司介绍优化版 + 产品营销定位 + 差异化竞争策略 + 领英全套方案 + 开发信模板 + 社媒内容日历。

---

### 3.5 自动化定时任务（业务员每日工作引擎）

> 详细设计见 [外贸业务知识库.md - 第十二章](外贸业务知识库.md)

将外贸业务员的每日工作规律固化为 Hermes cron 定时任务，Agent 按时触发、自动准备内容、业务员只需执行和复制粘贴。

**核心机制**：利用 Hermes 内置 cron 系统（`cron.create_job`），根据外贸业务员的每日工作流程，自动创建 7 个定时任务。Agent 到时间自动执行 prompt，生成可执行的内容推送给业务员。

**7 个定时任务一览**：

| 时间 | 任务 | 触发动作 |
|------|------|---------|
| 08:00（工作日） | 早安简报 | Agent 总结昨日互动 + 今日待跟进清单 + 客户时区窗口提醒 |
| 09:30（工作日） | 领英内容发布 | Agent 生成本日 Post + Article 草稿（可直接复制粘贴发布） |
| 10:00（工作日） | 欧洲客户开发信 | Agent 筛选欧洲客户 → 生成跟进邮件 → 业务员发送 |
| 11:00（工作日） | B2B 平台数据检查 | Agent 检查平台询盘、产品排名、同行动态 |
| 14:00（工作日） | 社媒内容发布 | Agent 生成 FB / Ins / TikTok 帖子 |
| 16:00（工作日） | 北美客户开发信 | Agent 筛选北美客户 → 生成跟进邮件 → 业务员发送 |
| 17:30（工作日） | 每日工作总结 | Agent 汇总今日数据 → 追加到工作日报 |
| 17:30（每周五） | 周报生成 | Agent 汇总本周日报 → 生成周报 |

**初始化方式**：
```
trade cron setup-trade-tasks
```
一键创建全部定时任务，无需手动配置。

### 3.6 标准化数据目录（`~/.trade/`）

> 详见 [Trade数据目录结构设计.md](Trade数据目录结构设计.md)

参考 Hermes `~/.hermes/` 设计，为每个公司建立标准化的本地 Markdown 知识库。结构统一、文件名固定、渐进填充。

**顶层结构**（`~/.trade/` 或 `%LOCALAPPDATA%\trade\`）：
```
.trade/
├── companies/{slug}/              # 公司（每个一个目录，8 个固定文件）
│   ├── company-profile.md         # 公司介绍
│   ├── products.md                # 产品目录与优势
│   ├── business-scope.md          # 业务范围
│   ├── agent-identity.md          # Agent 角色定义
│   ├── competitors.md             # 同行分析
│   ├── certifications.md          # 资质认证
│   ├── marketing-strategy.md      # 营销策略
│   ├── sales-playbook.md          # 销售手册
│   ├── libraries/{lib}/           # 文档库（3 个固定文件 + extracts/）
│   │   ├── index.md               # 文件索引
│   │   ├── changelog.md           # 内容变化记录
│   │   ├── metadata.md            # 元信息
│   │   └── extracts/{file}.md     # 文档分析切片
│   └── clients/{client}/          # 客户（7 个固定文件）
│       ├── profile.md             # 客户画像
│       ├── contacts.md            # 联系人
│       ├── interactions.md        # 交流记录与禁忌
│       ├── requirements.md        # 需求记录
│       ├── quotes.md              # 报价历史
│       ├── orders.md              # 订单记录
│       └── notes.md               # 备注
```

**核心设计**：每个公司目录下文件名完全相同，初始为空模板，内容逐步填充。Agent 启动时自动读取当前公司的 `agent-identity.md` 作为角色定义。

**初始化命令**：`trade init-company --name "公司名" --slug "slug"`

### 3.7 客户管理

- 客户 CRUD + 关联文档库（多对多）
- 每个客户的报价单、合同、沟通记录独立管理
- 客户画像自动汇总（从多份文档中提取客户相关信息）

### 3.8 首次运行引导（Onboarding）

> 新用户首次打开应用时，引导完成公司注册和 Agent 身份配置，一步到位。
> 新增于 2026-05-12。

**用户流程**：

```
首次打开 /trade
    │
    ├─ GET /api/trade/onboarding/status
    │      └─ {done: false}  → 显示引导页面
    │
    └─ POST /api/trade/onboarding/first-company
           Body: {company_name, contact_name, contact_email,
                  identity_data: {role, products, differentiation, target_region}}
           │
           ├─ company.create()              # 创建公司记录 + ~/.trade/{slug}/ 目录
           ├─ update_trade_company()        # 写入 agent_identity_md 到 DB
           ├─ 写入 ~/.trade/{slug}/agent-identity.md  # 文件备份
           └─ 返回 {company, trade_company}
                  └─ 前端跳转到正常聊天界面
```

**一体化 API**：

| 端点 | 方法 | 说明 |
|------|------|------|
| `/api/trade/onboarding/status` | GET | 返回 `{done: bool}`，前端据此决定显示引导页或正常 UI |
| `/api/trade/onboarding/first-company` | POST | 原子创建公司 + 配置 Agent 身份 |

**幂等保护**：`POST /onboarding/first-company` 在已有活跃公司时返回 409，前端刷新页面不会重复触发。

**Agent 身份模板**：

```markdown
## 公司身份配置

你是一家专业外贸公司的 AI 销售助手。

**公司名称**：{company_name}
**产品范围**：{products}
**差异化卖点**：{differentiation}
**目标市场**：{target_region}

**沟通风格**：专业、简洁、不废话...
```

**引导模块**：`trade/onboarding.py`（单一职责：引导状态检测 + 首次公司创建），`api.py` 仅做 HTTP 解析和响应组装。

### 3.9 对话记忆与知识图谱

- 对话历史跨会话延续（`conversations` 表）
- Cognee 知识图谱记忆：文档内容、客户需求、产品参数自动建立实体-关系连接
- Agent 主动使用 `cognee_remember` 存储重要事实，`cognee_recall` 跨会话召回

### 3.11 OSINT 客户背景调查与风险评估（升级版背调）

> 新增于 2026-05-12。源自客户背调对话中的真实需求：单一邮箱平台检测不够，需要多信号交叉验证。

#### 3.11.1 现状与差距

**当前 `b2b-email-intel` 的能力**：
- 仅检测邮箱在 121+ 主流平台的注册状态（`holehe`）
- 输出：平台名 | 是否注册 | 用户名 | 档案 URL

**对话揭示的真实背调需求**——完整尽职调查需要 5 个维度交叉验证：

| 验证维度 | 当前 | 目标 |
|---------|------|------|
| 邮箱平台注册 | ✅ `holehe` | 保留 |
| 域名注册信息 | ❌ 缺失 | WHOIS 查询（注册时间/注册商/到期时间） |
| 企业邮箱验证 | ❌ 缺失 | `@公司.com` vs Gmail/QQ 个人邮箱判断 |
| 网站技术栈 | ❌ 缺失 | BuiltWith 检测（WordPress/Shopify/自建） |
| 制裁名单筛查 | ❌ 缺失 | OFAC/UN/欧盟/中国制裁名单交叉比对 |

**核心洞察（来自对话）**：单一信号不够，需要多信号交叉验证。例如：
- LinkedIn 主页看起来真，但域名 3 个月前新注册 → 红旗
- 企业邮箱用的是 `gmail.com` 而非 `@公司.com` → 红旗
- 网站技术栈是免费博客平台 → 红旗

#### 3.11.2 多层验证架构

```
用户输入：公司名 / 邮箱 / 网站 URL
    │
    ├─────────────────────────────────────────────────────────────┐
    │  Layer 1: 邮箱基础检测（holehe，已有）                         │
    │  ├─ holehe 邮箱注册检测（121+ 平台）                          │
    │  └─ 输出：found_count, 社交档案 URL 列表                      │
    └─────────────────────────────────────────────────────────────┘
                          ↓
    ├─────────────────────────────────────────────────────────────┐
    │  Layer 2: 域名深度查询（新增）                                 │
    │  ├─ WHOIS 查询：注册时间 / 注册商 / 到期时间 / DNS 服务器      │
    │  ├─ 注册时间 < 1 年 → ⚠️ 新注册域名（骗子特征）                 │
    │  ├─ 注册时间 > 3 年 → ✅ 老域名（正常）                        │
    │  └─ BuiltWith 技术栈检测                                      │
    └─────────────────────────────────────────────────────────────┘
                          ↓
    ├─────────────────────────────────────────────────────────────┐
    │  Layer 3: 企业邮箱验证（新增）                                 │
    │  ├─ 提取邮箱域名：xxx@company.com → company.com               │
    │  ├─ 对比网站域名：company.com vs company.com                  │
    │  ├─ @gmail.com / @qq.com / @163.com → 🚩 个人邮箱红旗         │
    │  └─ @企业域名 → ✅ 企业邮箱（加分项）                          │
    └─────────────────────────────────────────────────────────────┘
                          ↓
    ├─────────────────────────────────────────────────────────────┐
    │  Layer 4: 制裁名单筛查（新增）                                  │
    │  ├─ OFAC (美国)                                            │
    │  ├─ UN Security Council (联合国)                           │
    │  ├─ EU Consolidated List (欧盟)                             │
    │  ├─ UK HM Treasury                                           │
    │  └─ 中国商务部不可靠实体清单                                  │
    └─────────────────────────────────────────────────────────────┘
                          ↓
    ┌─────────────────────────────────────────────────────────────┐
    │  Layer 5: LinkedIn 公司页验证（新增）                          │
    │  ├─ 域名 vs LinkedIn 公司主页域名一致性                        │
    │  ├─ 员工 LinkedIn 数量（反应公司规模）                         │
    │  └─ 公司成立时间 vs 域名年龄对比                               │
    └─────────────────────────────────────────────────────────────┘
                          ↓
              ┌───────────────────────────────────┐
              │  综合风险评分报告（结构化输出）         │
              └───────────────────────────────────┘
```

#### 3.11.3 工具选型（免费 + 无需 API 优先）

> **架构原则**：优先使用免费、无需 API Key 的工具。任何需要付费账号的工具（如 Hunter.io、RocketReach、Dun & Bradstreet）均标记为 🅱️ 可选，仅在用户自行提供账号时调用。核心检测逻辑必须能在零配置情况下完整运行。

| 层级 | 工具 | 用途 | 类型 | 费用 | API Key | 优先级 |
|------|------|------|------|------|---------|--------|
| L1 邮箱注册 | `holehe` | 121+平台注册检测 | Python库 | 免费 | 不需要 | ✅ 必选 |
| L2 WHOIS | socket WHOIS 协议 | 域名注册/到期/注册商 | stdlib socket | 免费 | 不需要 | ✅ 必选 |
| L3 企业邮箱 | MX DNS 查询 + 正则 | @公司.com vs Gmail | stdlib | 免费 | 不需要 | ✅ 必选 |
| L4 制裁名单 | OFAC CSV 下载 | OFAC/UN/EU 筛查 | HTTP + stdlib | 免费 | 不需要 | ✅ 必选 |
| L5 技术栈 | HTML 正则 + HTTP Header | 检测 Shopify/WordPress | stdlib | 免费 | 不需要 | ✅ 必选 |
| L6 LinkedIn | Google 搜索 `site:linkedin.com` | 公司页存在性验证 | browser_navigate | 免费 | 不需要 | ✅ 必选 |
| L3 扩展 | **Hunter.io** | 域名邮箱发现/企业邮箱验证 | Web API | 免费限额 | **需要** | 🅱️ 可选 |
| L6 扩展 | **LinkedIn API** | 员工数/公司详情 | Web API | 免费限额 | **需要** | 🅱️ 可选 |
| 全球公司 | **SEC EDGAR** | 美国公司 SEC 文件 | Web | 免费 | 不需要 | 🅱️ 可选 |
| 英国公司 | **Companies House** | 英国公司注册信息 | Web API | 免费 | 不需要 | 🅱️ 可选 |
| 中国公司 | **企查查/天眼查** | 中国公司工商信息 | 页面抓取 | 付费 | **需要** | 🅱️ 可选 |
| OFAC/UN/欧盟 | 制裁名单 | 公开 CSV | 免费 | 需实现下载解析 |
| LinkedIn | 公司页验证 | 网页抓取 | 免费 | `browser_navigate` |

#### 3.11.4 风险评分体系

**交叉验证评分卡**（每项独立打分，汇总为综合评级）：

```
✅ 加分项                              ⚠️ 减分项
─────────────────────────────────────────────────────
域名 > 3 年                           域名 < 1 年
有企业邮箱 (@公司.com)                  只用 gmail/qq/163
LinkedIn 公司主页存在且员工多           无 LinkedIn 公司页
网站技术栈正规（企业级）                 免费博客/临时建站工具
域名年龄 ≈ 公司成立时间                  域名比公司还老很多
WHOIS 注册信息完整                     WHOIS 隐私保护/信息缺失
不在任何制裁名单                        在任一制裁名单中出现
```

**综合评级定义**：

| 评级 | 条件 | 建议 |
|------|------|------|
| 🟢 低风险 | 加分项 ≥ 4 且无红旗 | 正常跟进 |
| 🟡 中风险 | 有 1-2 个红旗 | 谨慎跟进，要求更多验证 |
| 🔴 高风险 | 红旗 ≥ 3 或任一制裁名单命中 | 强烈建议拒绝，或高层特批 |

#### 3.11.5 实施优先级

| 优先级 | 改进项 | 工作量 | 对应模块 |
|--------|--------|--------|---------|
| 🔴 P0 | WHOIS 域名查询（`python-whois`） | 小 | `trade/osint.py` |
| 🔴 P0 | 企业邮箱验证（正则 + DNS MX 查询） | 小 | `trade/osint.py` |
| 🔴 P0 | 制裁名单筛查（OFAC/UN/欧盟 CSV 解析） | 小 | `trade/osint.py` |
| 🟡 P1 | BuiltWith 技术栈检测 | 中 | `trade/osint.py` |
| 🟡 P1 | LinkedIn 公司页验证（browser_navigate） | 中 | `trade/osint.py` |
| 🟢 P2 | 多国家公司注册信息查询（企查查/天眼查/Companies House） | 大 | 独立 skill |

#### 3.11.6 分国家/地区公司注册信息查询

对话中明确指出不同地区需要不同查询工具：

| 地区 | 工具 | 说明 |
|------|------|------|
| 🇺🇸 美国 | SEC EDGAR, Corporation Wiki | 上市公司信息披露，免费 |
| 🇬🇧 英国 | Companies House | 免费公开，公司注册信息 |
| 🇨🇳 中国 | 企查查、天眼查 | 需要 API 或页面抓取 |
| 🌐 全球 | Dun & Bradstreet | 付费，商业数据 |
| 🇦🇪 中东 | Oman Chamber of Commerce, DED (UAE) | 各国工商部门网站 |
| 🇮🇳 印度 | MCA India | 免费，公司注册信息 |

**注意**：企查查/天眼查无公开免费 API，建议通过 browser_navigate 模拟登录或页面抓取实现。

#### 3.11.7 API 设计

```python
# trade/osint.py

def domain_whois(domain: str) -> dict:
    """WHOIS 域名查询。

    Args:
        domain: 域名（如 "example.com"）

    Returns:
        {
            "domain": str,
            "registered": bool,
            " registrar": str,
            "creation_date": str,
            "expiry_date": str,
            "days_old": int,
            "age_category": "new" | "medium" | "old",
            "dns_servers": list[str],
            "registrant_name": str | None,
            "error": str | None,
        }
    """

def verify_corporate_email(email: str, website: str | None = None) -> dict:
    """验证企业邮箱 vs 个人邮箱。

    Args:
        email: 邮箱地址（如 "john@acme.com"）
        website: 可选，公司网站（用于域名交叉验证）

    Returns:
        {
            "email": str,
            "domain": str,
            "is_personal": bool,       # True = gmail/qq/163 等个人邮箱
            "is_corporate": bool,      # True = 企业域名邮箱
            "risk_flag": bool,         # True = 🚩 个人邮箱红旗
            "domain_match": bool | None,# website 提供时可验证
            "mx_found": bool,          # 是否检测到 MX 记录
            "suggestion": str,          # 行动建议
        }
    """

def check_sanctions(name: str, country: str | None = None) -> dict:
    """筛查制裁名单。

    Args:
        name: 公司名或人名
        country: 国家（用于缩小范围）

    Returns:
        {
            "query": str,
            "hits": [
                {"list": "OFAC", "matched_field": str, "score": float},
                {"list": "UN", "matched_field": str, "score": float},
                ...
            ],
            "is_sanctioned": bool,
            "risk_level": "none" | "low" | "medium" | "high",
        }
    """

def detect_tech_stack(url: str) -> dict:
    """BuiltWith 风格技术栈检测。

    Args:
        url: 网站 URL（如 "https://example.com"）

    Returns:
        {
            "url": str,
            "technologies": list[str],
            "platforms": list[str],   # ["Shopify", "WordPress", "CloudFlare"]
            "is_free_platform": bool, # True = 🚩 免费建站工具红旗
            "is_enterprise": bool,    # True = ✅ 企业级平台
        }
    """

def linkedin_company_verify(domain: str, company_name: str) -> dict:
    """LinkedIn 公司页验证。

    Args:
        domain: 公司域名（如 "acme.com"）
        company_name: 公司名称

    Returns:
        {
            "domain": str,
            "company_name": str,
            "linkedin_found": bool,
            "linkedin_url": str | None,
            "employee_count": str | None,
            "industry": str | None,
            "founded": int | None,
            "domain_match": bool,
        }
    """

async def osint_full_check(
    target: str,                    # 邮箱 / 域名 / 公司名（自动识别）
    *,
    include_sanctions: bool = True,
    include_tech_stack: bool = True,
    include_linkedin: bool = True,
) -> dict:
    """完整 OSINT 尽职调查（异步流式，适合 LLM 流式调用）。

    依次执行各层检测，每层完成立即 yield 结果。
    """
```

#### 3.11.8 输出报告格式

```json
{
  "target": "john@acme.com",
  "target_type": "email",
  "overall_rating": "medium",
  "overall_score": 65,
  "flags": ["personal_email_domain", "domain_age_new"],
  "layers": {
    "email_registration": {
      "rating": "good",
      "checked_count": 121,
      "found_count": 3,
      "profiles": ["GitHub", "LinkedIn", "Twitter"]
    },
    "domain_intel": {
      "rating": "warning",
      "domain": "acme.com",
      "age_days": 120,
      "age_category": "new",
      "registrar": "GoDaddy",
      "whois_warning": "域名注册 < 1 年"
    },
    "email_verification": {
      "rating": "danger",
      "is_corporate": false,
      "is_personal": true,
      "risk_flag": true,
      "suggestion": "使用个人邮箱 (gmail.com)，要求对方提供企业邮箱"
    },
    "tech_stack": {
      "rating": "neutral",
      "platforms": ["Shopify", "CloudFlare"],
      "is_free_platform": false,
      "is_enterprise": true
    },
    "sanctions": {
      "rating": "good",
      "is_sanctioned": false,
      "hits": []
    },
    "linkedin": {
      "rating": "good",
      "linkedin_found": true,
      "domain_match": true,
      "employee_count": "50-200"
    }
  },
  "recommendations": [
    "⚠️ 对方使用个人邮箱，建议要求对方提供企业邮箱后再深入谈判",
    "⚠️ 域名注册仅 120 天，属于新注册域名，配套信息待验证",
    "✅ LinkedIn 公司页存在且员工规模正常，可信度 +1",
    "✅ 未出现在任何制裁名单中"
  ]
}
```

---

## 四、交互方式

| 方式 | 入口 | 说明 |
|------|------|------|
| Web 聊天界面 | `http://127.0.0.1:9119/trade` | Sidebar + Chat 布局，SSE 实时展示 Agent 工具调用进度 |
| CLI 命令行 | `trade` | 终端交互式对话 |
| 管理面板 | `/dashboard` | React 后台（配置、会话、定时任务） |

---

## 五、输出质量标准

### 5.1 语言策略

- **单文档单语言**：面向海外客户全英文，面向国内客户全中文。禁止中英文混排
- 产品型号、SKU 保留原文不翻译

### 5.2 内容标准

- 所有输出内容（帖文、开发信、营销方案）**可直接复制粘贴使用**，不需要用户再修改格式
- 引用来源时标注 `📄 {文件名} | Sheet: {sheet} | Row: {行范围}`
- 不确定的信息明确告知用户，不编造数据
- 无占位符（"XXX"、"Lorem ipsum"、"[TBD]"），空缺信息宁可省略

### 5.3 业务文档生成规范（PPTX / DOCX / XLSX）

| 维度 | 标准 |
|------|------|
| 配色 | 最多 3 色，与行业匹配。不用通用蓝色 |
| 字号 | 标题 36-44pt，段落标题 18-24pt，正文 12-16pt |
| 表格 | 完整数据填充，深色表头 + 交替行背景 |
| 布局 | 每页有视觉元素（色条、卡片、图标），禁止纯文本框 |

### 5.4 行业知识

- 贸易术语：FOB / CIF / EXW / MOQ / Lead Time / T/T / L/C / Incoterms
- 货币识别：¥/CNY、$/USD、€/EUR、£/GBP
- 单位换算：mm ↔ inch、kg ↔ lb、MPa ↔ psi、°C ↔ °F
- 平台知识：阿里国际站运营规则、领英 B2B 开发方法、社媒内容最佳实践

---

## 六、知识与训练资料

> 详细内容见 [外贸业务知识库.md](外贸业务知识库.md)，整理自外贸培训资料。

Agent 需要被训练为外贸高级销售员，需要学习以下资料：

### 6.1 思维模式
- 高级销售员的思维方法论
- B2B 销售心理学和决策链路
- 外贸全流程：询盘 → 报价 → 谈判 → 成交 → 跟单
- 万花筒客户画像能力反推法（Product Power → Delivery Power → Brand Reality → Service Power）

### 6.2 业务技能
- 三种客户类型的沟通策略（价格敏感型 / 品质导向型 / 关系型）
- Account IQ 客户深度分析框架（战略优先级 → 关键挑战 → 财务信号 → 供应商痛点）
- GAP Selling 价值匹配法：[客户痛点] + [我方优势] = [破局方案]

### 6.3 平台知识
- 阿里国际站 / 中国制造网 / 独立站的运营规则和优化技巧
- 领英 5 维度营销法（Post 视频 / 照片 / 文章 / 投票 / 文档）
- 领英个人账号 5 板块优化（Headline / About / Skills / Experience / Media）
- Facebook / Instagram / TikTok / YouTube 社媒内容策略
- 海关数据 / 广交会数据的筛选和分析方法

### 6.4 输出模板
- 顾问式开发信（Account IQ Cold Email 结构）
- 领英加好友话术（≤300 字符）
- 客户分析报告（四维框架）
- 领英 Profile 全套优化（5 板块）
- 年度营销方案（计划表 + 可执行内容）

---

## 七、新公司 Onboarding 资料清单

新公司部署完整营销方案需要准备：

| 序号 | 资料 | 说明 |
|------|------|------|
| 1 | 公司介绍 | 自身核心优势。基础版可让 Agent 帮忙优化润色 |
| 2 | 产品介绍 | 产品册、产品参数表、行业产品范围清单 |
| 3 | 同行公司 | 同行公司名 / 链接（用于竞争分析和差异化定位） |
| 4 | 领英账号 | 公司主页 + 业务员个人账号（有则提供） |

---

## 八、项目历史与经验教训

### 8.1 VibeRAG 三版迭代（已废弃）

| 版本 | 架构 | 结果 |
|------|------|------|
| V0.21 | 纯向量检索（ChromaDB + embedding chunk） | 向量匹配度低于无关文档 |
| V2 | 纯 FTS + LLM 直接读文件 | 三位 AI 评审反对（语义召回缺失） |
| V3 改进版 | FTS 主召回 + 五路辅助 + LLM 精读片段 | 两周实测，与 Hermes 差距悬殊 |

### 8.2 五个致命架构问题

1. FTS 词面匹配漏召回
2. 页级截断丢上下文
3. 表格 JSON 化信息损耗
4. 单次 LLM 调用无纠错能力
5. 与 Hermes Agent Agent Loop 的差距

### 8.3 经验总结

- B2B 场景的本质是 Agent Loop + Tool Calling，不是检索管线
- Fork 成熟开源项目做底座，比自己造轮子更务实
- 不要低估表格解析和 OCR 的复杂度

---

## 九、已知问题与待办

| 问题 | 状态 |
|------|------|
| 自动化定时任务（7 个每日任务 + 周报） | ✅ 已实现（b2b-daily-automation） |
| B2B平台诊断与优化 | ✅ 已实现（b2b-platform） |
| 社媒内容策略与素材生成 | ✅ 已实现（b2b-social-media） |
| 领英营销方案 | ✅ 已实现（b2b-linkedin-marketing） |
| 海关数据/广交会数据挖掘 | ✅ 已实现（b2b-customs-data） |
| 客户分析与开发信 | ✅ 已实现（b2b-lead-generation） |
| 文档库管理（16种文件格式） | ✅ 已实现（b2b-document） |
| 新公司Onboarding向导 | ✅ 已实现（b2b-onboarding） |
| 客户管理（CRUD + 文档库关联） | ✅ 已实现（b2b-customer-mgmt） |
| 标准化数据目录（~/.trade/） | ✅ 已实现（b2b-data-directory） |
| 业务文档生成（PPTX/DOCX/XLSX） | ✅ 已实现（b2b-doc-generation） |
| Cognee 知识图谱记忆 | ✅ 已可用 |
| Agent `max_iterations=25` 过低 → 已修复为 90 | ✅ 已修复 |
| AI 高级销售员训练 | ✅ 已集成至 system prompt（trade/prompt.py） |
| B2B 前端客户管理 UI | 待开发 |
| 消息平台（Telegram / 微信 / 飞书）接入 | 规划中 |
| Windows 原生兼容性全面测试 | 待测试 |
| macOS 兼容性全面测试 | 待测试 |
| 跨平台安装脚本（macOS curl + Windows PowerShell） | 待开发 |
| b2b-osint WHOIS 域名查询（P0） | 待实现 |
| b2b-osint 企业邮箱验证（P0） | 待实现 |
| b2b-osint 制裁名单筛查（P0） | 待实现 |
| b2b-osint BuiltWith 技术栈检测（P1） | 待实现 |
| b2b-osint LinkedIn 公司页验证（P1） | 待实现 |

**Skills 清单**：已创建 15 个行业通用 skills（#15 chat-memory + #16 b2b-skill-generator 为后续新增），覆盖项目需求文档 3.1–3.11 全部核心功能。

---

## 十、Skills 实现清单

> 全部为行业通用设计（industry-agnostic），不包含特定产品或行业限制。

### Skills 总表

| # | Skill | 对应章节 | 触发条件 |
|---|-------|---------|---------|
| 1 | `b2b-document` | 3.3.1 文档库管理 | 分析文档、提取 PDF/Excel/Word 内容 |
| 2 | `b2b-platform` | 3.1.1 B2B平台诊断 | 阿里国际站/中国制造网店铺诊断 |
| 3 | `b2b-social-media` | 3.1.2 社媒内容策略 | FB/Ins/TikTok/YouTube 内容日历 |
| 4 | `b2b-linkedin-marketing` | 3.1.3 领英营销 | LinkedIn Profile/内容/开发信 |
| 5 | `b2b-lead-generation` | 3.2.2 客户分析与开发信 | 客户分析、冷邮件、跟进序列 |
| 6 | `b2b-customs-data` | 3.1.4 海关数据挖掘 | 海关进出口数据、广交会数据 |
| 7 | `b2b-onboarding` | 3.4 新公司部署 | 新公司全套营销启动方案 |
| 8 | `b2b-customer-mgmt` | 3.7 客户管理 | 客户生命周期、报价单、订单 |
| 9 | `b2b-daily-automation` | 3.5 每日自动化 | 7个定时任务、周报自动化 |
|| 10 | `b2b-data-directory` | 3.6 标准化数据目录 | ~/.trade/ 目录结构、文件模板 |
|| 11 | `b2b-doc-generation` | 3.10 业务文档生成 | PPTX/DOCX/XLSX 专业文档 |
|| 12 | `b2b-email-intel` | 3.11 客户背景调查 | 邮箱 OSINT 背景调查（120+平台） |
|| 13 | `b2b-osint` | 3.11 升级版背调 | WHOIS + 企业邮箱验证 + 制裁名单 + 技术栈 + LinkedIn 交叉验证 |
| 15 | `chat-memory` | 3.13 对话长期记忆 | 历史查询工具，按时间范围/关键词查 DB，支持 Hindsight 向量检索 |

#

---

## 3.12 Prompt 隔离架构（用户可编辑的 System/Skill Prompt）

> 新增于 2026-05-12。系统所有注入 LLM 的 prompt 均支持用户编辑，文件优先、DB 缓存。

### 3.12.1 架构原则

| 原则 | 说明 |
|------|------|
| **文件是 Source of Truth** | `~/.trade/` 下的 `.md` 文件是 prompt 的权威来源 |
| **DB 是运行时缓存** | `agent_identity_md` 等字段为文件的热缓存，文件变更自动生效 |
| **mtime 缓存** | 避免每次请求重复读文件，文件变更后自动失效重载 |
| **Skill 从 SKILL.md 读** | `injection_prompt` 存在于 `SKILL.md` frontmatter，用户改 skill 文件即改行为 |

### 3.12.2 Prompt 文件布局

```
~/.trade/                                  # 运行时数据（.gitignore）
├── prompts/
│   └── system.md                         # 全局 system prompt（用户可编辑）
├── companies/{slug}/
│   └── agent_identity.md                 # 公司级 agent identity（覆盖全局 system）
└── companies.db                          # agent_identity_md 字段 = 热缓存

~/.hermes/skills/b2b-osint/
└── SKILL.md                              # injection_prompt 在 frontmatter
```

### 3.12.3 读取优先级

**System Prompt（纵向覆盖，取最高优先级）：**
1. `~/.trade/companies/{slug}/agent_identity.md` — 公司级
2. `~/.trade/prompts/system.md` — 全局自定义
3. 代码 fallback（`trade/prompt.py` 的 `TRADE_SYSTEM_PROMPT`）

**Skill Injection（纵向覆盖，取最高优先级）：**
1. `~/.hermes/skills/{skill}/SKILL.md` frontmatter 的 `injection_prompt`
2. 代码 fallback（`skill_router.py` 的 `_SKILLS` 字典）

**最终拼接（横向）：**
```
system_prompt + skill_injection + doc_context + user_query
```

### 3.12.4 文件变更自动生效

`trade/prompts.py` 维护 mtime 缓存（`_PROMPT_CACHE`）：
- 文件 `mtime` 未变 → 直接用缓存
- 文件 `mtime` 变化 → 重新读文件，更新缓存
- 用户 `vim ~/.trade/prompts/system.md` 后下次请求自动生效，无需重启

### 3.12.5 实施文件

| 文件 | 作用 |
|------|------|
| `trade/prompts.py` | 统一 prompt 文件加载器（mtime 缓存） |
| `trade/skill_router.py` | 从 SKILL.md frontmatter 读取 `injection_prompt` |
| `trade/helpers.py` | 改用 `prompts.resolve_system_prompt()` |
| `trade/onboarding.py` | 写 identity 文件 + DB 双写 |
| `.trade-template/prompts/system.md` | system prompt 安装模板 |
| `.trade-template/companies/company-slug/agent_identity.md` | agent identity 安装模板 |


## 3.13 对话长期记忆与历史查询

> 新增于 2026-05-12。解决"今天不知昨天事"——所有对话永久带时间戳存储，Agent 可随时主动查询。

### 3.13.1 核心原则

- **所有对话永久存**：不压缩、不摘要、不丢弃，`created_at` 是必填字段
- **默认注入少量最近历史**：10-20 轮（~10k tokens），保证近期上下文连贯
- **更早历史按需查询**：Agent 通过工具主动查，LLM 根据工具描述自行判断时机
- **阈值由代码控制**：用户完全不可感知
- **Hermes 原生记忆互通**：`save_with_context()` 每次保存对话后，自动将摘要写入 `~/.hermes/memories/MEMORY.md`，Hermes Agent 跨项目也能记住 B2B 业务对话

### 3.13.2 Token 预算分配

| 区段 | 上限 | 说明 |
|------|------|------|
| System prompt | ~5k | 公司 identity + doc context |
| Skill injection | ~1k | 当前触发的 skill augment |
| **Recent history** | **~10k** | **固定 10-20 轮，最近上下文** |
| Current query | ~1k | 用户本次问题 |
| Reserved space | ~83k | 留给 Agent 推理和响应 |

### 3.13.3 Prompt 构建逻辑（build_query）

**阈值判断对象：整个 prompt 的 token 总数**

```python
# 阈值硬编码，不暴露给用户
if total_tokens < 20_000:
    history_limit = 20   # 充足空间，注入更多历史
    hint = None
elif total_tokens < 50_000:
    history_limit = 10    # 开始压缩历史量
    hint = "如需更早的对话历史，请使用 chat_memory_list 工具。"
else:
    history_limit = 5     # 强制精简
    hint = "当前上下文较长，历史对话已精简。如需查询更早内容，请使用 chat_memory_list 工具。"
```

**History 注入始终为固定轮数（history_limit），不随阈值无限增长。**

### 3.13.4 工具描述驱动（无触发词）

Agent 何时查历史不由触发词决定，而由工具描述决定：

```json
{
  "name": "chat_memory_list",
  "description": "查询与当前公司的历史对话记录。当用户提到'之前''上次''以前'等时间相关词汇，
                 或询问过去讨论过的内容时，使用此工具检索相关历史。",
  "parameters": {
    "time_range": {
      "type": "string",
      "enum": ["today", "this_week", "this_month", "all"],
      "description": "时间范围：今天/本周/本月/全部"
    },
    "limit": {
      "type": "integer",
      "default": 20,
      "description": "返回的最大消息数"
    }
  }
}
```

LLM 读取 SKILL.md 的工具描述后，自行判断何时需要调用——用户说"你上次推荐的那个供应商叫什么"时，LLM 会主动查 `chat_memory_list`。

### 3.13.5 Hindsight 与 SQLite 的分工

| 查询类型 | 示例 | 存储/检索 |
|---------|------|---------|
| **时序查询** | "昨天的对话"、"上周谈了什么" | SQLite `ORDER BY created_at` |
| **语义查询** | "那个做芯片的供应商"、"之前提到的方案" | Hindsight 向量检索 |

- 有 Hindsight API Key → 时序用 SQLite，语义用 Hindsight
- 无 Hindsight API Key → 语义查询降级为 SQLite `WHERE query LIKE '%关键词%'`

### 3.13.6 实施计划

| 优先级 | 内容 | 文件 |
|--------|------|------|
| ~~P0~~ ✅ | `build_query()` 注入最近 10-20 轮历史 + token 阈值 hint | `helpers.py` |
| ~~P0~~ ✅ | `chat-memory` skill：SKILL.md + 工具描述（无触发词） | `skills/chat-memory/` |
| ~~P0~~ ✅ | `chat_memory_list(time_range, limit)` 函数 | `chat_memory.py` |
| P1 | `chat_memory_summarize(days)` 摘要函数 | `chat_memory.py` |
| P1 | `memory.retain()` 每次对话后异步写入 Hindsight（可选） | `memory.py` |
| P2 | Agent 主动语义回忆（判断"这是在说上次那件事"） | 后续迭代 |
| ~~P2~~ ✅ | `retain_to_hermes_memory()` 写入 `~/.hermes/memories/MEMORY.md` | `memory.py` |

## AI 高级销售员

> 非独立 skill，已内置于 `trade/prompt.py` 的 system prompt。

- 对应章节：3.2.1 AI 高级销售员
- 训练资料：高级销售员的思维
- 能力：客户类型判断、价格谈判、跟进分类、异议处理

### Skills 目录位置

```
skills/
├── b2b-document/           # 原有
├── b2b-platform/            # 新增
├── b2b-social-media/       # 新增
├── b2b-linkedin-marketing/ # 新增
├── b2b-lead-generation/     # 新增
├── b2b-customs-data/        # 新增
├── b2b-onboarding/          # 新增
├── b2b-customer-mgmt/       # 新增
├── b2b-daily-automation/   # 新增
├── b2b-data-directory/      # 新增
├── b2b-doc-generation/     # 新增
├── b2b-email-intel/        # 新增
└── b2b-osint/             # 新增（WHOIS + 企业邮箱 + 制裁名单 + 技术栈）
```

---

## 十一、跨平台开发检查清单

> 每次提交代码前，确认以下项目在两个平台上均可通过。

### 路径与文件

- [ ] 所有路径操作使用 `pathlib.Path`，无硬编码 `/` 或 `\`
- [ ] 文件名仅含小写字母、数字、连字符、下划线、点号
- [ ] 目录层级 ≤ 3 层
- [ ] 读写文本文件显式指定 `encoding='utf-8'`
- [ ] 不使用 Windows 保留名称（CON、PRN、AUX、NUL、COM1-COM9、LPT1-LPT9）

### 进程与命令

- [ ] 不在代码中拼接 shell 命令字符串
- [ ] 子进程调用使用 `subprocess.run([...])` 列表形式
- [ ] 系统级命令（如 `rm`、`cp`）使用 Python 标准库替代（`os.remove`、`shutil.copy`）

### 网络与端口

- [ ] 默认绑定 `127.0.0.1`（非 `localhost`，避免 IPv6 解析差异）
- [ ] 端口号可配置（`--port` 参数）

### 数据与配置

- [ ] 用户数据存储在 `TRADE_HOME` 下（不硬编码路径）
- [ ] 配置读取使用 `TRADE_HOME` 环境变量 + 合理的平台默认值
- [ ] 换行符由 Python 自动处理（`newline=None` 读，`\n` 写）

---

## 十二、升级逻辑（数据完整性保护）

> Trade 升级时必须保证原有业务数据（数据库、公司目录文件）完整可用，
> 不能因 schema 变更而丢失任何用户数据。新增于 2026-05-12。

### 12.1 设计原则

| 原则 | 说明 |
|------|------|
| **向后兼容** | 新版本代码必须能读写旧版本写入的数据 |
| **自动迁移** | 启动时自动检测并执行迁移，无需用户手动干预 |
| **原子性** | 迁移失败时数据库回滚，不留下半成品状态 |
| **幂等性** | 迁移脚本可安全重复执行，不会重复插入数据 |
| **可逆性** | 迁移脚本有清晰的 `up()` / `down()` 逻辑（用 Python 而非 SQL 注释实现） |

### 12.2 迁移检测机制

每次 `init_db()` 执行时，数据库层按以下顺序检测当前 schema 版本：

```
1. 读取 PRAGMA table_info(libraries) — 获取当前列集合
2. 判断 "company_id" 列是否存在
   ├─ 不存在 → v0 schema（单公司版本）
   └─ 存在   → v1 schema（多公司版本）
3. 后续版本检测同理，逐版本递进
```

**重要**：不使用独立的 `schema_version` 表，而是通过检测关键列是否存在来判断版本。
原因：避免多表写入增加原子性风险；列存在即代表该版本迁移已完成。

### 12.3 版本演进与迁移路径

#### v0 → v1：单公司 → 多公司（Multi-Tenancy）

**触发条件**：检测到 `libraries` 表无 `company_id` 列。

**迁移前数据状态**（v0）：
```
libraries:     id, name, root_path, description, created_at, updated_at
customers:     id, name, contact, note, created_at, updated_at
conversations: id, query, response, files_read, created_at
```

**迁移后数据状态**（v1）：
```
companies:        id, name, slug, logo_url, website, contact_name, ...,
                 extra1='{}', extra2='{}', extra3='{}'
trade_companies: company_id(PK), data_dir, agent_identity_md, is_active, created_at,
                 extra1='{}', extra2='{}', extra3='{}'
libraries:       + company_id (FK → companies(id), DEFAULT 1),
                 extra1='{}', extra2='{}', extra3='{}'
customers:       + company_id (FK → companies(id), DEFAULT 1),
                 extra1='{}', extra2='{}', extra3='{}'
conversations:   + company_id (FK → companies(id), DEFAULT 1),
                 extra1='{}', extra2='{}', extra3='{}'
```

**迁移操作步骤**（`database.py:_migrate_from_v0()`）：

```
Step 1: 创建新表
  CREATE TABLE companies (...)
  CREATE TABLE trade_companies (...)
  INSERT OR IGNORE INTO companies (name='我的公司', slug='default', ...)
  INSERT OR IGNORE INTO trade_companies (company_id=1, data_dir='', ...)

Step 2: ALTER TABLE（逐表添加列）
  ALTER TABLE libraries     ADD COLUMN company_id INTEGER REFERENCES companies(id) ON DELETE CASCADE
  ALTER TABLE customers     ADD COLUMN company_id INTEGER REFERENCES companies(id) ON DELETE CASCADE
  ALTER TABLE conversations ADD COLUMN company_id INTEGER REFERENCES companies(id) ON DELETE CASCADE

Step 3: 填充 company_id（现有数据全部归属公司 1）
  UPDATE libraries    SET company_id = 1
  UPDATE customers    SET company_id = 1
  UPDATE conversations SET company_id = 1

Step 4: 创建索引
  CREATE INDEX idx_libraries_company     ON libraries(company_id)
  CREATE INDEX idx_customers_company     ON customers(company_id)
  CREATE INDEX idx_conversations_company ON conversations(company_id)

Step 5: 补充备用列（所有 6 张表）
  _add_spare_columns(conn)  # 幂等 ADD COLUMN，已存在则静默忽略
```

**数据完整性保证**：
- 所有现有数据自动归属公司 1（"我的公司"），不丢失任何记录
- 新表与旧表数据在同一个事务中完成，失败则整体回滚
- `ON DELETE CASCADE` 确保删除公司时自动清理其全部业务数据

---

#### v1 → v2（示例，未来扩展）

未来每个 schema 变更都遵循相同模式，在 `database.py` 中追加新的 `_migrate_v1_to_v2()` 函数：

```python
def _migrate_v1_to_v2(conn):
    # Step 1: 检测是否需要迁移（幂等性）
    cur = conn.execute("PRAGMA table_info(libraries)")
    cols = {row[1] for row in cur.fetchall()}
    if "new_column" in cols:
        return False  # 已迁移

    # Step 2: 执行迁移（在同一个事务中）
    conn.execute("ALTER TABLE libraries ADD COLUMN new_column TEXT DEFAULT ''")
    # ... 其他操作

    # Step 3: 补充备用列（未来每张新表均需）
    _add_spare_columns(conn)

    conn.commit()
    return True
```

### 12.4 目录文件迁移

公司数据目录（`~/.trade/{slug}/`）的迁移在 `company.py:_ensure_data_dir()` 中处理：

```
触发时机：company.create() 或 company.get() 时调用
触发条件：目标目录 ~/.trade/{slug}/ 不存在

迁移操作：
  1. 读取 .trade-template/ 作为源
  2. 在临时目录中复制模板
  3. 重命名占位符目录：
       companies/company-slug  → companies/{slug}
       libraries/library-slug  → libraries/{slug}
       clients/client-slug     → clients/{slug}
  4. 移动临时目录 → ~/.trade/{slug}/
```

**数据完整性保证**：
- `if target.exists(): return target` — 已存在的公司目录永远不会被覆盖
- 新公司使用模板创建，不影响已有公司的目录文件
- `shutil.move()` 是原子操作（在同一文件系统内）

### 12.5 升级失败处理

| 失败场景 | 处理方式 |
|---------|---------|
| 数据库迁移 SQL 执行失败 | `conn.rollback()` 回滚，进程退出并输出错误信息 |
| 公司目录创建失败 | `company.create()` 抛出异常，DB 事务未提交 |
| 模板目录不存在 | `_ensure_data_dir()` 静默创建空目录，不阻止公司创建 |
| 磁盘空间不足 | Python IOError，进程退出，DB 未写入 |

**日志输出**：
- 迁移开始：`Detected v0 schema — migrating to multi-company v1 …`
- 迁移完成：`Migration complete. Default company '我的公司' (slug=default) created.`
- 迁移失败：完整的 SQLite 错误信息，便于诊断

### 12.6 版本降级（Downgrade）

Trade **不支持**从高版本降级到低版本。降级操作需要用户手动：
1. 备份 `~/.trade/` 目录和 `data/trade.db`
2. 重新安装旧版本 pip 包
3. 手动还原数据

降级保护原因：ALTER TABLE 不可逆（SQLite 不支持 DROP COLUMN），降级可能导致数据丢失。

### 12.7 升级前检查清单（维护者用）

每次发布新 schema 变更前，必须确认：

```
[ ] 新迁移函数已实现 up() 逻辑，幂等性已验证
[ ] 在旧版本数据库上执行迁移，所有现有数据不丢失
[ ] 新版本数据库回滚到迁移前状态，验证 rollback 有效
[ ] 迁移后公司目录结构正确（companies/{slug}/ 等目录名已重命名）
[ ] 前端能正确访问迁移后的公司数据（X-Company-ID 路由正常）
[ ] 单元测试覆盖迁移路径（test_v0_to_v1_migration）
```

---

*文档源：*
- `trade/database.py` — `_migrate_from_v0()` 迁移实现
- `trade/company.py` — `_ensure_data_dir()` / `_rename_template_placeholders()` 目录迁移
- `trade/library.py` / `trade/customer.py` / `trade/chat_memory.py` — company_id 字段隔离
