@AGENTS.md
AI-native 投研自动化流水线:将 KOL 社交媒体内容转化为结构化、可回测、可审计的投资事件。
- 主语言:Python(遵循 PEP 8,类型注解必须完整)
- 前端:TypeScript(Next.js 16 + React 19 + TailwindCSS 4)
- 后端:Python 3.11+ (FastAPI + Pydantic V2)
- 代码比例:Python ~170 文件,TypeScript ~40 文件
OpenADE 作为多 Agent 管理器打开 Claude Code 时,Claude Code 不会自动加载 Codex 的 skill registry。反过来,Codex 也不会自动加载 Claude Code 的 agents/commands。需要两边共同遵守的规则必须沉淀到本仓库。
本仓库的共享入口:
AGENTS.md:Codex / OpenAI agent 的项目入口,包含 F0-F8 架构边界与 Agent 执行规则。CLAUDE.md:Claude Code 的项目入口,包含工程纪律、验证命令与工作流规范。src/finer_dashboard/AGENTS.md与src/finer_dashboard/CLAUDE.md:前端目录级补充规则,只能收紧或补充根目录规范,不得放宽。knowledge/okf/:OKF derived knowledge layer(跨工具可读的架构知识导航;非运行时真值,契约见docs/specs/2026-06-26-okf-knowledge-bundle.md)
执行规则:
- 在本仓库内工作时,任何 Agent 都必须遵守根目录
AGENTS.md和CLAUDE.md。 - 私有 skill/agent 只作为工具增强,不作为项目规范真相源。
- 如果 Codex skill、Claude Code agent/command 与项目文件冲突,以项目文件为准。
- 新增跨工具长期规则时,优先更新
AGENTS.md/CLAUDE.md,不要只写入某个客户端的私有目录。 - 能力层共享使用 Claude Code skills 机制:个人技能位于
~/.claude/skills/<skill-name>/SKILL.md。需要把 Codex /~/.agentsskills 同步到 Claude Code 时,运行scripts/sync_claude_skills_from_codex.sh;该脚本只新增缺失 skill,不覆盖已有同名 skill。
Canonical pipeline: F0-F8。 详见 AGENTS.md 和 docs/ARCHITECTURE.md。
旧命名 L0-L8 和 V0-V6 已废弃(deprecated),仅保留于 docs/ARCHITECTURE.md 第16章 Legacy Mapping 供迁移参考。
F0 (Intake) → F1 (Standardize) → F1.5 (Topic Assembly) → F2 (Anchor) → F3 (Intent) → F4 (Policy) → F5 (Execute) → F6 (Review) → F7 (Timeline) → F8 (Backtest)
| F-stage | 代码目录 | 职责 | 可调用 |
|---|---|---|---|
| F0 | ingestion/ |
多源数据接入(飞书/B站/微信) | services/llm.py, services/converter.py |
| F1 | parsing/ |
内容标准化:结构边界、standardization quality、provenance | services/llm.py, services/perception.py |
| F1.5 | parsing/topic_assembler.py |
长篇复杂内容主题组装(TopicBlock);只处理语义边界 | schemas/content_envelope.py, schemas/topic_block.py |
| F2 | enrichment/ |
实体锚定、质量评估、时间解析 | services/finance_skills_client.py, entity_registry.py |
| F3 | extraction/intent_extractor.py |
投资意图提取 | services/llm.py |
| F4 | policy/ |
Intent→TradeAction policy 映射 | 规则引擎(无 LLM) |
| F5 | extraction/trade_action_extractor.py |
TradeAction 生成 | services/llm.py, services/finance_skills_client.py |
| F6 | api/routes/ |
人工审核、RLHF 反馈收集 | services/, ml/ |
禁止:
- 跨 F-stage 直接调用(如 F5 直接调 F1)
- 在 API route 中写业务逻辑(route 只做参数解析和响应格式化,逻辑放
services/) - F3 生成 TradeAction(F3 职责止于 Intent)
- F5 不经过 F3/F4 直接从原始文本生成 TradeAction
- F1.5 解析 F1 原始格式细节(markdown heading、HTML wrapper、OCR bbox、ASR timestamp)
- 新 F1 代码输出 legacy
SegmentRecord作为 canonical 结果
公共模块(任何 F-stage 可调用):
services/llm.py— LLM 统一调用services/finance_skills_client.py— 金融数据(带 TTL 缓存)services/kol_registry.py— KOL 注册表(configs/creators/*.yaml 只读真值,TTL 缓存;任何 F-stage 可查询)schemas/— 数据契约config.py,paths.py,manifests.py— 配置与路径
跨期持续性检验结论:券商的历史超额胜率不能预测其未来超额(两个指标、 六个切分点、预声明判据双双不成立)。产品定位相应转为 「不告诉你谁更准,让你查得清谁说过什么」。
由此产生两条硬纪律,写代码时不得绕过:
- 样本充分 ≠ 可以预测。
SampleSufficiency.tier与predictive_claim.permitted是两个独立的门。任何比率离开后端必须 携带sufficiency;前端按display_policy呈现,count_only时 不得渲染任何比率。未检验的指标一律permitted=false。 - 口径隔离。
signal_class三值——broker_recommendation(个股评级)/broker_sector_view(板块观点)/kol_statement——基准率不同, 不得混在同一张记分卡里比较。 - 排行榜不按超额排序。 默认序 = 已结算样本量;超额列保留但强制并排 95% 区间与「不构成对未来的预测」声明。禁止「Top 券商」式文案。
相关:docs/specs/2026-08-02-positioning-pivot-proposal.md(定位与模块判定)、
2026-08-02-crd2-significance-gate.md(效力门)、docs/ARCHITECTURE.md §8.5。
新建或改动的 API 错误必须使用 canonical error envelope(见 src/finer/errors/)。每个错误必须携带 request_id、stage、operation、retryable、fix_hint;F0 导入错误还必须携带 source_channel。
旧路由中尚未迁移的错误响应由 verification agent 报告并逐步收敛,不允许为了“一次性清零”做无边界全量迁移。
详见 docs/specs/2026-05-parallel-agent-execution.md Line F 章节。
唯一真相源:src/finer/schemas/ 下的 Pydantic 模型。
- 数据结构变更只改 Pydantic 模型,不改 JSON Schema
/schemas/目录下的 JSON Schema 保留为文档参考,标注<!-- AUTO-GENERATED, DO NOT EDIT -->- 新增字段必须有
Field(description=...)说明 - 前端
contracts.ts必须与 Pydantic 模型字段名、类型一致
ContentRecord (F0)
└→ ContentEnvelope (F1)
└→ ContentBlock + BlockQuality + BlockProvenance (F1)
└→ TopicBlock / TopicAssemblyResult (F1.5)
└→ QualityCard + TemporalAnchor + EntityAnchor + EvidenceSpan (F2)
└→ NormalizedInvestmentIntent (F3)
└→ PolicyMappingResult (F4)
└→ TradeAction + ExecutionTiming (F5)
└→ ViewpointState (F7) → BacktestResult (F8)
旧 L0/L3/L5 命名仅在
pipeline/orchestrator.py(legacy orchestrator)和data/目录结构中保留。Schema 定义、API 契约、文档均以 F-stage 为准。 F1 标准化契约以docs/specs/f1-standardization-contract.md为准。旧 V0 block type、legacySegmentRecord、L3 perception 只能作为迁移输入,不是新代码的 canonical output。 F1.5 是 F1/F2 之间的 mandatory sub-stage,用于把长聊天、长文档等 multi-topic 内容组装为TopicBlock,但不改变 F0-F8 顶层命名。规则版 TopicAssembler 只作为 baseline/fallback,主方向是 constrained LLM proposal + deterministic validator。
修改 Pydantic schema 后,必须同步修改:
src/finer_dashboard/src/lib/contracts.ts— TypeScript 类型定义- 相关 API route 的请求/响应模型
- 前端组件中使用该类型的代码
枚举漂移自动防护:pydantic Literal/Enum ↔ contracts.ts 字符串枚举的值集一致性由 scripts/check_contract_drift.py 守护(pytest tests/test_contract_drift.py 自动跑)。新增/改动镜像枚举时,若脚本报「unmapped TS enum」或值集 drift,在 REGISTRY 登记映射或修正值集;纯前端枚举登记进 UI_ONLY_TS_ENUMS。无 clean Literal 的取值集(如 canonical_trace_status/instrument_type)先在 schema 提模块级 *_LITERAL 常量再引用,保证单一真相源。
- 路由文件放
src/finer/api/routes/ - 单文件不超过 500 行(当前
files.py已超,需拆分) - 每个路由模块导出
router = APIRouter(prefix=..., tags=[...]) - 在
server.py中统一注册
# 成功
{"ok": true, "data": {...}}
# 错误
{"ok": false, "error": {"code": "NOT_FOUND", "message": "..."}}- 按资源实体拆分(files、review、rlhf、extraction...)
- 同一资源的操作超过 8 个端点时,按操作类型拆子路由
- CRUD + 列表 = 一个文件;复杂业务流程(如 RLHF)独立文件
| 场景 | 主模型 | 降级模型 |
|---|---|---|
| 文本富化/分类 | GLM-5.1 (SVIPS) | Qwen-Plus (DashScope) |
| 图像 OCR/图表分析 | MiMo-V2.5 | — |
| 结构化提取 (Instructor) | Qwen-Max | — |
模型注册表在 model_config.py。F1 vision/OCR 当前固定为 mimo-v2.5,不启用视觉模型 fallback。
调用 MiMo 前必读 docs/mimo-integration-guide.md(端点按 key 前缀分流否则 401、
max_completion_tokens 字段名、thinking:{"type":"disabled"} 省 89-97% token、
429 的三种含义与判据、批量作业骨架)。该指南的结论均有实测背书,勿凭记忆重新发明。
- Prompt 模板写在调用方模块内,不单独抽文件
- 使用 Jinja2 模板(
jinja2已是依赖)或 f-string - 复杂 prompt(如 DPO 训练模板)放
ml/目录 - 禁止在 prompt 中硬编码 API key 或敏感信息
结构化输出必须用 instructor + Pydantic response model:
from instructor import patch
client = patch(OpenAI(...))
result = client.chat.completions.create(
model="qwen-max",
response_model=MyPydanticModel,
messages=[...]
)data/F0_intake/ ← ingestion/ 写入
data/F1_standardized/ ← parsing/ 写入(标准化后内容)
data/F2_anchored/ ← enrichment/ 写入
data/F3_intents/ ← extraction/ 写入(Intent)
data/F4_policy_mapped/ ← policy/ 写入
data/F5_executed/ ← extraction/ 写入(TradeAction)
data/F6_reviewed/ ← review 流程写入
data/F7_timeline/ ← timeline/ 写入
data/F8_metrics/ ← backtest 写入
当前磁盘目录仍为 L0-L8 命名,迁移映射详见
docs/ARCHITECTURE.md第16章。
data/raw/ ← 原始文件,按 creator 组织
data/processed/ ← manifests, documents, transcripts
data/rlhf/ ← RLHF 反馈数据
data/cache/ ← 应用缓存,可安全清理
- Content manifest:
{content_id}.manifest.json - Segment:
{content_id}_{segment_idx}.json - Event:
{content_id}_{event_idx}.event.json - TradeAction:
{ticker}_{timestamp}.action.json
- 每个内容必须有
ContentManifest - manifests 索引懒加载,API 层用 TTL 缓存
- 修改 manifest 后必须更新索引
必须有测试的模块:
extraction/— 事件提取核心逻辑enrichment/— 市场数据融合、情绪融合parsing/— 文本解析、slang 映射schemas/— Pydantic 模型序列化/反序列化api/routes/— API 端点基本可用性
不要求测试的模块:
ingestion/— 依赖外部服务(飞书/B站),用 smoke test 覆盖ml/— 训练流程,手动验证services/— 外部 API 客户端,mock 测试可选
- 测试文件放
tests/,命名test_{module}.py - 测试数据放
tests/fixtures/ - 使用
pytest,运行命令:pytest tests/ -v - Mock 外部服务(LLM API、finance-skills),不 mock 内部逻辑
- Schema 测试覆盖:序列化、反序列化、字段校验、默认值
# 后端
pytest tests/ -v
# 前端
cd src/finer_dashboard && npm run build
# 类型检查(如有配置)
cd src/finer_dashboard && npx tsc --noEmit
# 审计闭环(改动 F3/F4/F5 后必跑,必须 100%)
# 退出码:0 = 全部完整;1 = 有断链;2 = 空扫描(什么都没验,见下)
python scripts/audit_trace_integrity.py
# 读模型投影重建(改动 CRD 视图字段后必跑,否则页面静默用旧 payload)
python scripts/materialize_projections.py在 worktree 里跑数据类验证必须显式指向主仓。 data/ 已 gitignore,worktree
的 data/ 是空的,而 §10 又要求并行 agent 优先用 worktree——两条规范叠加的结果是
数据门在 worktree 里扫 0 条然后判绿。审计脚本现在会以退出码 2 拒绝空扫描,
但你仍要自己把 root 指对:
python scripts/audit_trace_integrity.py --data-root /Users/zhouhongyuan/Desktop/finer/data| 文件 | 内容 | 是否 gitignore |
|---|---|---|
.env |
API 密钥(MIMO_API_KEY, GLM_API_KEY, DASHSCOPE_API_KEY) | 是 |
configs/*.yaml |
服务配置(飞书、creator profiles) | 否(敏感字段用占位符) |
configs/*.yaml.example |
配置模板 | 否 |
src/finer/config.py |
配置加载器 | 否 |
- 新增配置项先加到
config.py的 dataclass,再写 YAML - 敏感值(key、token、secret)只放
.env,代码中通过os.environ读取 configs/下的 YAML 可提交,但不含真实密钥
finer.cli.main() 在做任何事之前调用 ops/env_bootstrap.load_env_file()——
模型注册表在 import 期就读密钥,晚一步就拿不到。此前整条流水线路径没有
任何地方加载 .env,能跑通全靠启动 shell 恰好 export 过;换 shell 或换
launchd 任务就报「模型没配」,与真因隔着一层。
两条约束:已存在的环境变量优先(文件是兜底不是权威);标准库实现,
不引 python-dotenv(它没在 pyproject.toml 里声明)。
直接 import 模块而不走 CLI 的脚本,需要自己调一次 load_env_file()。
- Python: 遵循 PEP 8,类型注解必须完整
- TypeScript: 使用 ESLint(
npm run lint) - 命名:Python 用 snake_case,TypeScript 用 camelCase,Schema 字段用 snake_case
- Commit message:
type(scope): description- type: feat / fix / refactor / docs / test / chore
- scope: ingestion / enrichment / extraction / api / dashboard / schemas / ml
- 不提交
data/目录、.env、__pycache__、.venv
- 在对应层目录下创建模块
- 定义 Pydantic schema(如涉及新数据结构)
- 写 API route(如需前端访问)
- 同步
contracts.ts(如涉及前端) - 补测试(如在关键路径上)
- 更新
config.py(如有新配置项)
- 不注释掉报错代码来消除警告
- 不在代码中硬编码密钥、token
- 不在 API route 中写业务逻辑
- 不跳过分层直接跨层调用
- 不修改 JSON Schema(只改 Pydantic 模型)
# 安装(含行情数据可选依赖)
pip install -e '.[dev,market-data]'
# 后端 API
uvicorn finer.api.server:app --reload --port 8000
# 前端 Dashboard
cd src/finer_dashboard && npm run dev
# CLI
python -m finer.cli init-storage
python -m finer.cli feishu-sync
# 测试
pytest tests/ -v涉及多条任务线、多 Agent、或跨 3+ 模块的开发,必须先阅读并遵守:
docs/specs/2026-05-parallel-agent-execution.md
每轮实现型并行任务启动前,必须先运行或读取 Line V 只读门控规范:
docs/specs/2026-05-verification-snapshot-gate.md
Line V 的输出是当前仓库 baseline report;后续实现型 Agent 必须基于该报告声明 ownership、冲突文件和验证命令。
并行任务启动前必须声明:
- parallel line(如 F0 Intake Repair、F3-F4-F5 Canonical Path、F8 Backtest)
- 所属 F-stage
- 输入 schema 与输出 schema
- 允许修改文件
- 禁止修改文件
- 验收命令
强制规则:
- 一个实现型 Agent 只能拥有一个 F-stage、一个明确 frontend surface,或一个只读 verification 任务。
- Line V Verification Snapshot 是实现型并行任务的前置门控;它只能读文件、运行测试/build/rg/git diff,并输出 baseline report,不得修改任何文件。
- 共享 contract 先冻结,再允许下游并行;渠道 Agent 不得私自扩展
ContentRecord。 - 第一轮并行优先级:并行规范 -> ERR-0/ERR-1 错误反馈基础 -> A0 F0-Core -> A1 Project Memory contract -> A2 分渠道导入 -> A3 Import Console -> KOL Backtest MVP。
- F0 只输出
ContentRecord、raw archive、import receipt/status、F0 local index;不得做 OCR、topic assembly、entity/time anchor、intent、TradeAction、backtest。 - F0 Project Memory 以 raw 文件和
ContentRecord/manifest 为可重建依据,SQLite 只能作为热索引;Finer OS 启动默认不得递归扫描 raw 目录。 - 新增或修改 SQLite 表结构、旧数据迁移、批量重建、批量删除,必须先获得用户确认。
- F0 渠道导入按来源拆分为飞书、本地上传、NotebookLM、微信、B站;共享文件如
integrations.py、contracts.ts必须单 agent 串行修改或先拆分 ownership。 - 新建或改动的错误响应必须使用 Line F canonical envelope;必须包含
request_id、stage、operation、retryable、fix_hint,F0 还必须包含source_channel。 - 错误 details 禁止出现 token、secret、password、cookie、authorization、api_key。
- 新主链路不得依赖 legacy
TradeActionExtractor.extract_from_text();F5 canonicalTradeAction必须包含intent_id、policy_id、evidence_span_ids、execution_timing。 - F0 Import Console 只能展示导入状态和项目内存健康状态,不得把“导入成功”显示为“解析成功”。
- F0 Import Console 必须展示错误码、request_id、retryable、fix_hint;不得展示原始 traceback、token、cookie 或 auth header。
- 多 Agent 并行写代码时优先使用独立 git worktree 或独立分支;不得让两个实现型 Agent 在同一工作目录修改重叠文件。
- Verification Agent 默认只读,只能读文件、运行命令、报告发现;不得顺手改业务代码。
涉及 3+ 问题 的复杂调试场景,使用并行 Agent 模式:
- 每个 Agent 独立调查一个问题
- 所有 Agent 完成后汇总发现
- 统一应用修复,避免冲突
- 并行数量控制在 3-4 个,避免超时
示例场景:
- 同时诊断 B站/微信/Trade Action/F-stage 边界/摘要生成等多个问题
- 跨 10+ 文件的重构验证
开始多文件操作前,确认工作目录正确:
# 确认在项目根目录
pwd # 应为 /Users/zhouhongyuan/Desktop/finer如果遇到目录问题,重启会话到正确位置。
CLI 命令(如 claude mcp add、claude --version)在系统终端执行,不要粘贴到 Claude 会话中。
复杂多步骤工作使用 TaskCreate/TaskUpdate 追踪进度:
- 每个子任务独立创建
- 开始时标记
in_progress - 完成后立即标记
completed - 依赖关系用
blockedBy声明
触发条件:单次任务耗时超过 10 分钟(累计处理、分析、修改时间),完成后必须产出结构化审阅文档。
docs/specs/{YYYY-MM-DD}-{任务简述-kebab-case}.md
任务简述例:f-stage-migration、intent-extractor-rewrite、image-preview-fix
每个文档必须包含以下核心段:
- 概述(Overview):一句话说清任务目标与结果
- 变更清单(Changes):文件路径 + 变更类型(新增/修改/删除),用列表或表
- 架构影响(Architecture Impact):说明对分层边界、数据流、API 契约的影响,引用受影响的 schema / route / contract
- 关键决策(Key Decisions):本次做了什么选择、为什么(不一定要多,但要捕捉非显而易见的决策)
- 验证结果(Verification):跑了什么命令、输出是什么、是否全部通过
- 未解决项(Open Issues):本次未覆盖的已知缺口(如没有则写「无」)
- 文件路径使用从项目根开始的相对路径:
src/finer/extraction/intent_extractor.py:142 - Schema 引用:
schemas/contract.py:AssetFile - API 端点引用:
GET /api/files?tier=F1 - 外部系统:用完整 URL(如 Grafana dashboard、Linear ticket)
- 只在聊天里口述结论性摘要,不落地为文件
- 写一个 README 式的浏览文档,不包含具体变更路径和验证输出
- 把聊天内容直接复制粘贴当文档