Files
MoFin/docs/llm-execution-protocol.md
T
xxm 61c3cb52b2 docs: LLM执行协议开发规范+可复用JSON schema
- docs/llm-execution-protocol.md: 从重评流程提取的通用协议(输入/prompt/解析/校验/写入/错误处理)
- specs/schemas/reassess-output.json: 重评LLM输出节标题schema
- specs/schemas/trade-capture-output.json: 截图识别LLM输出schema
- 可复用组件: _section_line/snapshot_strategy_history/write_holding_strategy/门禁模式
2026-08-21 00:08:09 +08:00

255 lines
7.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# LLM 执行协议(开发规范)
> 任何"LLM 输出 → 代码校验 → 写入 DB"的场景,必须遵循本协议。
> 本协议从重评流程(batch_reassess)提取,适用于所有 LLM→DB 交互。
---
## 一、协议总览
```
输入数据 → Prompt模板 → LLM输出 → 节标题解析 → 代码校验 → DB写入 → 确认反馈
```
**核心原则**
1. **LLM 只输出文本**,不直接写 DB
2. **代码层做所有校验**LLM 输出不可信)
3. **写入前快照**,失败可恢复
4. **白名单控制写入权限**(不是所有 source 都能写所有字段)
---
## 二、输入数据层
### 2.1 数据来源规范
| 数据类型 | 来源 | 层级 | 示例 |
|---|---|---|---|
| 价格 | stock_daily.close / live_prices.price | 采集层 | 收盘价/盘中价 |
| 基本面 | stock_fundamentals.pe/mcap | 加工层 | PE/市值 |
| 技术指标 | ta.full_analysis() / stock_indicators | 加工层 | 支撑阻力/MA/RSI |
| 策略参数 | holding_strategies | 业务层 | entry/stop/tp |
| 消息面 | signal_news | 采集层 | 新闻摘要 |
| 资金流 | capital_flow_cache | 采集层 | 净流入/主力 |
| 组合状态 | portfolio_summary + holdings | 业务层 | 总资产/持仓股数 |
**铁律**:使用层不得直接调 API 采集数据。所有数据必须从 DB 表读取(由采集层写入)。
### 2.2 数据收集函数
每个 LLM 任务实现一个 `collect_data(code)` 函数:
- 从各表读取数据
- 填充 `data` dict
- 返回给 build_prompt 使用
---
## 三、Prompt 模板规范
### 3.1 结构
```
角色定义(一句话)
【输入数据段1】(系统提供,非 LLM 生成)
【输入数据段2】
...
【输出格式要求】(节标题列表 + 每个字段的约束)
⚠️ 输出纪律(必须遵守)
1. 直接以【节标题】开头
2. 禁止寒暄/开场白
3. 所有【】节标题一个都不能少
```
### 3.2 节标题设计原则
- **每个字段一个节标题**(如 `【买入区间】``【建议止损】`
- **节标题行首匹配**(不使用关键词包含)
- **一个字段一个值**(禁止节标题内嵌套多个值)
- **"无"显式表达**(如 `【买入区间】无`,不写 `0.0~0.0`
### 3.3 输出纪律
prompt 末尾必须包含:
```
⚠️ 输出纪律:
1. 直接以【xxx】开头
2. 禁止寒暄
3. 所有【】节标题一个都不能少
4. 每个字段只填一个值
```
---
## 四、解析层(parse_response
### 4.1 节标题解析器
```python
def _section_line(text, name):
"""从 LLM 输出中提取指定节标题的内容"""
for line in text.split("\n"):
if re.match(r'^\s*【' + name + r'】', line):
return line
return ""
```
**规则**
- 行首匹配(可含空白)
- 只认精确节标题(不用 "包含xxx的第一行"
- 返回整行内容(含节标题本身)
### 4.2 解析约束
每个字段的解析必须包含:
- **类型校验**:数字字段必须是数字
- **范围校验**:如仓位必须 1-30%
- **一致性校验**:止损 < 区间下沿 < 区间上沿 < 止盈
- **空值处理**:显式 "无" → 清空;空字符串 → 跳过(保留原值)
---
## 五、校验层(save_result / 门禁)
### 5.1 门禁清单
| 门禁 | 规则 | 失败行为 |
|---|---|---|
| 空输出 | LLM 返回空/无节标题 | 拒绝写入 |
| 区间合理性 | 下沿 < 上沿 < 下沿 × 3 | 跳过区间写入 |
| 区间偏离 | 区上沿 < 现价 × 0.5 或 区下沿 > 现价 × 1.5 | 拒写并清空 |
| 止损锚定 | 止损 ≥ 区间下沿 | 用技术位修正 / 拒写 |
| 信号一致性 | 操作建议否定买入但信号是"买入" | 降级为"关注" |
| 数量正整数 | 股数必须 > 0 且为整数 | 拒绝写入 |
| 代码存在性 | 股票代码必须在 stock_daily 中存在 | 拒绝写入 |
### 5.2 门禁输出
每个门禁失败必须:
1. 打印 `⚠️` 日志(含具体原因和数值)
2. 跳过该字段写入(保留原值)或拒绝整个写入
3. **不能静默失败**
---
## 六、写入层
### 6.1 写入前操作
```python
snapshot_strategy_history(conn, code, source_trigger) # 快照
```
### 6.2 写入权限(白名单)
```python
_PARAM_WHITELIST = ('per_stock_12d', 'batch_12d', 'promote')
if source_trigger not in _PARAM_WHITELIST:
# 非白名单 source:保留 DB 当前参数值
```
### 6.3 写入后操作
- 返回确认信息给调用方
- 触发必要的联动(如快照、信号同步)
---
## 七、错误处理
### 7.1 LLM 调用失败
```
重试 → 升级模型 → 最终失败则跳过该股票
```
### 7.2 解析失败
```
节标题未找到 → 该字段跳过(保留原值)
所有字段跳过 → 拒绝写入
```
### 7.3 写入失败
```
DB 异常 → 回滚到快照 → 打印错误
```
---
## 八、可复用组件
### 8.1 `_section_line(text, name)` — 节标题解析器
- 位置:batch_reassess.py
- 用途:从 LLM 输出提取指定节内容
- 通用性:✅ 任何 LLM 输出解析都可复用
### 8.2 `snapshot_strategy_history(conn, code, source)` — 写入前快照
- 位置:mofin_db.py
- 用途:记录修改前状态,失败可恢复
- 通用性:✅ 任何 DB 写入都应先快照
### 8.3 `write_holding_strategy(..., source_trigger)` — 白名单写入
- 位置:mofin_db.py
- 用途:按 source_trigger 控制写入权限
- 通用性:✅ 所有策略卡写入都走这个函数
### 8.4 门禁模式
```python
# 区间合理性门禁
if _el > 0 and _eh > _el and _eh < _el * 3:
# 合理,写入
elif _el > 0 or _eh > 0:
print("⚠️ 解析异常,跳过")
```
通用性:✅ 任何数值字段都可套用此模式
---
## 九、新场景接入清单
新增"LLM 输出 → 写入 DB"场景时,按以下清单逐项完成:
- [ ] 实现 `collect_data(code)` — 收集输入数据
- [ ] 实现 `build_prompt(data)` — 定义输出格式(节标题)
- [ ] 定义节标题列表 — 每个字段一个标题
- [ ] 实现 `parse_response(text)` — 按节标题解析
- [ ] 实现门禁逻辑 — 校验每个字段的合理性
- [ ] 选择写入函数 — 复用已有或新建
- [ ] 定义 source_trigger — 写入权限控制
- [ ] 测试:正常输入 → 正常输出
- [ ] 测试:异常输入(空/越界/格式错误)→ 正确拒绝
- [ ] 测试:并发写入 → 不互相覆盖
---
## 十、示例:截图识别更新持仓
### 输入
用户发交易截图 → 知微 LLM 解析
### 输出格式
```
【交易动作】买入 / 卖出
【股票代码】600262
【股票名称】北方稀土
【交易数量】500
【交易价格】15.20
【交易时间】2026-08-20 14:30
```
### 门禁
- 交易动作:必须是"买入"或"卖出"
- 股票代码:6位数字,必须在 stock_daily 中存在
- 交易数量:正整数,卖出时不超过当前持仓
- 交易价格:正数,与现价偏差不超过 ±10%
### 写入
- 买入 → INSERT OR REPLACE holdingsshares += 交易数量)
- 卖出 → UPDATE holdingsshares -= 交易数量,shares=0 时标记 is_active=0
- 写入后自动调用 clean_watchlist(自选池进出管理)