这份工程 PRD 服务工程师而非利益相关方, 回答"怎么把它造出来 / 各部分契约是什么 / 什么算做完了"。三条写作原则: 契约先行(Pydantic schema)、验收即测试(Given-When-Then)、Harness 与 Agent 解耦(2025-2026 agent 工程最重要范式转变)。
整个系统的最高层抽象是三个解耦的层。理解这三层的边界, 是理解后续所有设计决策的前提。
把 Harness 这一层进一步展开, 它由 8 个职责清晰的子系统组成。这套分层直接来自 2025-2026 年 agent harness 工程的业界共识。每个子系统单一职责、清晰边界, 可独立测试、独立替换。
持久化状态 · LangGraph + Postgres checkpointer · 任何会话可中断可恢复
决定下一步执行哪个节点 · 如何恢复失败的步骤
接近窗口上限时压缩(compaction) · 工具结果清理 · 子代理上下文隔离
把 agent 动作意图分发到正确的 MCP 工具
隔离执行不可信代码
守住凭证边界 · agent 永远看不到数据库密码或 API key
记录全过程 · Langfuse 自托管 + OpenLLMetry 埋点
对结果做评判 · 确定性检查 + LLM-as-judge · 人工校准
数据模型是系统的契约基础。Pydantic 既是运行时的校验器, 也是文档, 还是测试的基准。标的标识统一为 MARKET:TICKER, 内部一律用统一 ID, 避免 A 股六位数字、港股五位数字、美股字母代码在系统里混用导致路由错误。
class Security(BaseModel): uid: str # 统一 ID, 如 "SH:600519" market: Market ticker: str # 原始代码, 如 "600519" name_cn: str | None name_en: str | None currency: str # CNY / HKD / USD sector_gics: str | None sector_sw: str | None # 申万行业 class FinancialStatement(BaseModel): uid: str period: str # "2025A" / "2025Q3" revenue: float | None net_income: float | None operating_cash_flow: float | None # 关键指标跨源校验, 差异 > 10% 时打 flag data_quality_flag: bool = False source: str class ResearchReport(BaseModel): report_id: str uid: str template: ReportTemplate # quick_note / deep_dive / sector / earnings_recap sections: list[ReportSection] rating: Rating | None # buy / hold / sell target_price: float | None version: int # 支持版本 diff disclaimer: str # 强制非空, 免责声明
M1 是地基, 其余全部依赖。任何 M1 延期会向后传导。M3 和 M4 可在 M2 完成后并行。
每条决策有主要依据和可逆点, 让团队理解"为什么是它" 而非"为什么不是别的"。
| 编号 | 决策 | 选择 | 主要依据 | 可逆点 |
|---|---|---|---|---|
| ADR-01 | 后端语言 | Python | 金融数据库与 agent SDK 生态全在 Python | 几乎不可逆 |
| ADR-02 | 编排框架 | LangGraph | 生产可控、checkpointing、可观测最强 | 退化单 agent 可降级 OpenAI Agents SDK |
| ADR-03 | 结构化输出 | Pydantic + 原生 | 事实标准, 生成层强制 schema 最可靠 | 不可逆 |
| ADR-04 | 真相源数据库 | PostgreSQL / TimescaleDB | 时序分块 + 列式压缩 + 连续聚合 | 可迁移 |
| ADR-05 | 分析层 | DuckDB / Parquet | 进程内 OLAP, 直查 Parquet, 适合回测扫描 | 可替换 |
| ADR-06 | 向量库 | pgvector → Qdrant | 小规模同栈起步, 规模化迁 Rust 强过滤库 | 迁移成本=重建索引 |
| ADR-07 | 可观测性 | Langfuse 自托管 + OpenLLMetry | 开源、OTel 原生、可气隙、避免锁定 | 可换 backend |
| ADR-08 | MCP 框架 | FastMCP | 兼容最新 spec、Streamable HTTP、OAuth | 可替换 |
| ADR-09 | 私有推理 | vLLM + Qwen/DeepSeek | PagedAttention 高吞吐, 数据主权 | 仅机构场景启用 |
| ADR-10 | 能力分层 | Skills(知识)+ MCP(数据计算) | 数据会变用 MCP, 知识稳定用 Skill | 边界可调 |
这些是设计约束, 也是最终验收的依据。性能用 P95 / P99 而非平均值, 因为 LLM 系统里平均延迟会掩盖让用户抓狂的长尾。
| 维度 | 指标 | 目标值 |
|---|---|---|
| 性能 | 深度调研端到端 P95 延迟 | ≤ 10 分钟 |
| 性能 | 快速调研端到端延迟 | ≤ 4 分钟 |
| 性能 | 缓存命中响应 | ≤ 100 ms |
| 性能 | 并发会话 | ≥ 20 |
| 成本 | 单次深度调研 token 成本 | ≤ $0.5 |
| 成本 | 预算护栏告警 / 熔断 | 80% / 100% |
| 可靠性 | 单市场单源数据可用率 | > 99% |
| 可靠性 | 缓存命中率 | > 80% |
| 可观测 | trace 覆盖 | 100% LLM/工具调用 |
| 质量 | Skill 调用成功率(MVP/差异化) | ≥ 90% / ≥ 95% |
| 安全 | 第三方 Skill / MCP 上线前审计 | 100% |
在 agent 系统里, 模糊性是最大的成本来源。本文档为每个 Skill / MCP 工具 / API 端点都给出明确的接口契约和 Pydantic 数据模型, 防止集成时崩溃。
所有功能需求附 Given-When-Then 验收标准, 设计成可直接转化为离线 eval 数据集或自动化测试用例。"系统应该准确" 不可验收, "DCF 在 WACC=8.5% / g=3% 下输出每股内在价值落在 1760-2140" 可验收。
大模型每升级一次, 围绕它搭建的复杂度就要被重新定价。解耦的架构让我们能在不动核心业务逻辑的前提下, 既给 harness 做加法, 也做减法。