【个人记账理财助手】大模型上下文管理选型文档
【个人记账理财助手】 大模型上下文管理选型文档一、背景与目标在我们的记账应用中Text-to-SQL 的每轮查询都需要将一段上下文塞进 LLM 的上下文窗口让模型理解库长什么样和怎么查。这段上下文包含三部分上下文类型内容体积特点DDL表结构定义users, accounts, transactions, categories…~5-10 KB相对固定偶有变动业务文档分类体系、金额规则、时间表达规范~3-5 KB基本固定示例 SQL(问题, SQL) 问答对高频查询每个 pair ~0.5-2 KB持续增长按需检索核心矛盾所有上下文加起来远超 LLM 的上下文窗口即使 DeepSeek-V3 有 128K也不意味着把所有东西无脑塞进去效果就好——检索噪声会拉低准确率。本文档的目标选型一套上下文管理策略在有限的上下文窗口内只放最相关的信息让 Text-to-SQL 准确率最高、token 消耗最少。二、核心问题什么是好的上下文2.1 上下文过量的代价全部 DDL 全部文档 全部示例 SQL → 塞进 prompt 后果 ├── 检索噪声不相关的表结构干扰 LLM 判断 ├── Lost in the Middle关键信息被淹没在长文本中间位置 ├── Token 浪费每次请求都花冤枉钱DeepSeek ¥2/百万输入 token └── 延迟增加长 prompt 的首 token 生成时间更长2.2 上下文不足的代价只塞 DDL不给示例 SQL → LLM 自己猜怎么写 后果 ├── 准确率低没有 few-shot 的约束SQL 风格随意 ├── 不理解业务语义外卖和餐饮的层级关系需要 example 才能学会 └── 时间表达混乱没有示例上个月可能被翻译成不同的 SQL目标在太多和太少之间找到最优平衡点。三、上下文管理全景对比3.1 可选策略一览策略核心思路Token 节省准确率影响实现复杂度全量注入所有 DDL 文档 示例一次性塞入0%基准中噪声干扰低RAG 检索语义检索最相关的 DDL/文档/示例~60-80%高前提是检索准中分层检索先查表级 → 再查列级 → 再查示例 SQL~70-85%高精确匹配中高上下文压缩用 LLM 或专用模型压缩 prompt 长度~40-60%中高有信息损失高KV Cache 复用重复部分的 Key-Value 缓存前缀缓存~30-50% 推理无损失依赖 API 支持规则引擎降级高频简单查询不走 LLM走预置模板~90% 调用无损失精确匹配低多 Agent 分工不同 Agent 负责不同表/任务各自小上下文~50-70%高需编排高3.2 记账场景的适配策略在我们场景中的适用性理由全量注入❌ 不推荐~15 张表 文档 示例超出合理范围RAG 检索✅核心策略Vanna 本身基于 RAG已有社区实践分层检索✅推荐增强记账场景表多但关联明确分层检索效果更好上下文压缩⚠️ 可选对 DDL 做压缩可能丢失列注释等关键信息KV Cache 复用✅ 可选DeepSeek 支持 prefix caching可缓存 DDL 前缀规则引擎降级✅推荐本月总支出等高频查询直接走模板0 token 成本多 Agent 分工❌ 过度设计10 张表以内不需要多 Agent单人记账场景简单最终推荐策略组合RAG 检索 分层检索 规则引擎降级。四、策略一RAG 检索基础层4.1 Vanna 默认的 RAG 流程提问 → 向量检索DDL 文档 示例 SQL→ 拼装 prompt → LLM 生成 SQL Vanna 的做法把所有训练数据DDL/documentation/sql向量化 查询时用 cosine similarity 找 top-k 最相关的片段。4.2 默认方案的问题混合检索导致精度稀释DDL、文档、示例 SQL 在同一向量空间类型差异大互相干扰表级 vs 列级不分一张大表的 DDL 作为一个 chunk检索到整张表但实际只需要其中两列未利用结构关系记账表之间存在外键关联transactions → categories纯向量检索不知道这种关系4.3 改进方向问题 → 改进 ─────────────── 混合检索 → 分类型独立索引 粗粒度 → 分层检索表级 → 列级 → 示例 无结构 → 引入 schema 关联图五、策略二分层检索增强层推荐5.1 三层检索架构用户提问这个月外卖花了多少钱 │ ▼ ┌─────────────────────────────────────┐ │ Layer 1表级路由 │ │ 判断问题涉及哪些表 │ │ 结果transactions categories │ └──────────────────┬──────────────────┘ ▼ ┌─────────────────────────────────────┐ │ Layer 2列级 条件提取 │ │ 哪几列什么过滤条件 │ │ 结果amount, transaction_date │ │ category.name 外卖 │ │ transaction_date 本月 │ └──────────────────┬──────────────────┘ ▼ ┌─────────────────────────────────────┐ │ Layer 3示例 SQL 匹配 │ │ 检索最相似的问题-SQL pair │ │ 结果找到本月餐饮花了多少的 SQL │ └──────────────────┬──────────────────┘ ▼ 拼装最终 prompt精简、精准5.2 每层的具体设计Layer 1 — 表级路由输入这个月外卖花了多少钱 输出[transactions, categories] 实现方式 ┌── 方案 Aembedding 匹配将表描述向量化检索最相关的 │ transactions → 交易记录表金额、时间、类型、分类 │ categories → 分类表名称、父分类 │ → 匹配到 transactions 和 categories │ └── 方案 B关键词匹配简单可靠适合固定表名 花了多少钱 → amount属于 transactions 外卖 → category name属于 categories → 命中 transactions categories 推荐方案 Aembedding为主方案 B 做降级兜底Layer 2 — 列级 条件提取输入这个月外卖花了多少钱 输出 聚合列SUM(amount) 过滤条件transaction_type expense category.name 外卖 或 c.parent.name 餐饮 transaction_date BETWEEN 2026-05-01 AND 2026-05-31 实现用一个轻量 LLM 调用或规则做问题 → 结构化条件抽取 这一层输出的不是 SQL而是业务条件 → 后面组装 SQL 更容易Layer 3 — 示例 SQL 匹配输入这个月外卖花了多少钱 输出最相似的 (question, sql) pair 检索策略按优先级 1. exact match相同问题 → 直接复用 SQL最高优先级 2. 同义词 match外卖 vs 餐饮 → 替换分类名后复用 3. embedding match语义相近的问题 → 作为 few-shot 示例 检索量控制top-3太多会稀释注意力实验表明 3-5 个示例效果最佳5.3 最终 prompt 拼装组装后的 prompt约 2-3K token仅为全量的 1/10 系统你是个人记账 SQL 专家... 相关表结构 transactions(id, user_id, amount, transaction_type, transaction_date, category_id) -- 金额正数expense 表示支出 categories(id, name, parent_id) -- 外卖的父分类是餐饮 业务规则 金额单位人民币元 这个月 date_trunc(month, CURRENT_DATE) ~ now() 分类查询需考虑子类 参考示例 Q: 这个月餐饮花了多少 A: SELECT SUM(amount) FROM transactions t JOIN categories c ON t.category_id c.id WHERE t.transaction_type expense AND (c.name 餐饮 OR c.parent_id (SELECT id FROM categories WHERE name餐饮)) AND t.transaction_date date_trunc(month, CURRENT_DATE) 问题这个月外卖花了多少钱六、策略三规则引擎降级兜底层6.1 适用场景对于高频、简单、确定的查询直接走预置模板不调 LLM查询类型示例模板本月总支出“这个月花了多少钱”SELECT SUM(amount) FROM transactions WHERE ...本月总收入“这个月收入多少”同上改 type ‘income’账户余额“支付宝还有多少钱”SELECT balance FROM accounts WHERE name LIKE %支付宝%按分类汇总“本月餐饮花了多少”模板 分类参数近 N 天流水“最近 7 天的支出”SELECT ... WHERE date now() - interval 7 days6.2 如何与 RAG 配合请求进入 │ ├──→ 规则匹配意图分类→ 命中 → 执行模板 SQL → 返回 │ └──→ 未命中 → RAG 检索 → LLM 生成 → 执行 → 返回 ↓ 如果用户确认了正确 SQL → 反哺为模板6.3 效果典型场景80% 的用户查询是本月花了多少餐饮支出这类简单查询 规则引擎覆盖这 80% → LLM 调用减少 80% → 延迟从 ~3s 降到 ~10ms 剩余 20% 复杂查询走 LLM环比、自定义时间段等七、上下文压缩何时需要7.1 压缩 vs 检索的取舍检索推荐精确选择要什么不要什么 ✅ 无信息损失 ✅ 可控性强 ❌ 依赖检索质量 压缩备选全拿来然后压缩 ✅ 不会遗漏信息 ❌ 有信息损失关键列注释可能被压缩掉 ❌ 多一次 LLM 调用成本7.2 记账场景的压缩策略对于 DDL不需要通用压缩——更好的做法是结构化精简 原始 DDL约 1.5 KB/表 CREATE TABLE transactions ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID NOT NULL REFERENCES users(id), amount NUMERIC(15,2) NOT NULL CHECK (amount 0), ... ); 精简后约 0.3 KB/表保留业务语义 transactions(user_id, amount, transaction_type[income/expense/transfer], transaction_date, category_id→categories) -- amount 正数 表示 expense 方向为正 压缩率~80%且无信息损失去掉了通用约束、默认值等 LLM 不需要的细节7.3 什么时候真正需要压缩DeepSeek 不支持 prefix caching 时可以用压缩减少输入 token表结构超过 20 张分层检索加压缩结合用户一次问多个问题批量查询压缩历史对话八、各方案的综合对比维度全量注入RAG 检索分层检索规则降级上下文压缩Token 消耗基准~20-40%~10-20%~0-10%~40-60%准确率BIRD 基准中等较高高精确中高实现复杂度低中中高低高可维护性低中中高低冷启动速度立即需向量化训练需分层训练需模板积累立即覆盖查询面100%依赖检索依赖检索仅高频100%记账场景推荐❌✅ 基础✅ ✅核心✅ 兜底⚠️ 备选九、综合推荐方案9.1 推荐架构用户提问 │ ▼ ┌────────────────────────────────────────────┐ │ ① 规则引擎 │ │ 意图分类 → 高频简单查询 → 执行模板 SQL → 返回│ └──────────────────┬─────────────────────────┘ │ 未命中 ▼ ┌────────────────────────────────────────────┐ │ ② 分层检索核心 │ │ Layer 1: 表级路由 → 命中哪些表 │ │ Layer 2: 列级条件提取 → 具体查啥 │ │ Layer 3: 示例 SQL 匹配 → top-3 few-shot │ └──────────────────┬─────────────────────────┘ ▼ ┌────────────────────────────────────────────┐ │ ③ Prompt 拼装 │ │ 只包含命中表 相关文档 匹配示例 │ │ 体积控制在 ~2-3K token │ └──────────────────┬─────────────────────────┘ ▼ ┌────────────────────────────────────────────┐ │ ④ DeepSeek API │ │ (利用 prefix caching 缓存 DDL 片段) │ └──────────────────┬─────────────────────────┘ ▼ SQL 执行 结果返回9.2 Token 预算分配每次查询的 token 预算~3K约全量的 1/10 ┌────────────────────────────────────┐ │ Token 预算分配 │ │ │ │ System Prompt 200 (7%) │ │ 命中的表 DDL 800 (27%) │ │ 相关业务文档 500 (17%) │ │ few-shot 示例 1200 (40%) │ │ 用户问题 300 (10%) │ ├────────────────────────────────────┤ │ 总计 ~3000 token │ └────────────────────────────────────┘ vs 全量注入~20-30K token 节省~85-90%同时提高准确率9.3 演进路线Phase 1MVP—— 规则引擎 简单 RAG └── 覆盖 80% 高频查询的规则模板 └── Vanna 默认 RAGDDL 文档 示例统一检索 └── top-5 检索结果拼装 Phase 2增强—— 分层检索 └── 表级路由embedding 关键词双通道 └── 列级条件提取轻量 LLM 调用 └── 示例 SQL 分层匹配exact → synonym → semantic └── token 预算动态分配按问题复杂度调整 Phase 3优化—— 持续学习 └── 用户修正 SQL → 自动归入规则模板 or 增强示例库 └── A/B 测试不同检索策略的准确率 └── 热力图分析哪些查询类型容易失败定向补充训练数据十、风险评估风险概率影响缓解检索不准确导致错误 SQL中高分层检索规则兜底后大幅降低前端保留 SQL 预览确认环节规则模板覆盖不足中低模板逐步积累而非一步到位未命中时平滑降级到 LLMDDL 变更后向量库过期低中CICD 流水线中加一步DDL 变更 → 自动重新训练 Vanna中文时间表达解析错误中中Layer 2 做时间标准化将上个月这周转为具体日期范围token 预算不足低低128K 窗口远超预算压缩策略做最后兜底十一、总结最终推荐规则引擎降级 分层 RAG 检索 组合策略。层级方案覆盖成本第一层规则模板~80% 高频查询~0 token~10ms第二层分层 RAG 检索~18% 中低频查询~3K token~1-2s第三层全量检索兜底~2% 极端复杂查询~10K token~3-5s与数据库选型和应用上下文管理组合┌──────────────────────────────────────────┐ │ 应用上下文 (ContextVar) │ │ user_id / request_id 贯穿全栈 │ ├──────────────────────────────────────────┤ │ LLM 上下文管理 (本选型) │ │ 规则引擎 → 分层检索 → prompt 拼装 │ ├──────────────────────────────────────────┤ │ Text-to-SQL 引擎 (Vanna) │ │ RAG 检索 DeepSeek-V3 API 生成 SQL │ ├──────────────────────────────────────────┤ │ 数据层 (PostgreSQL) │ │ 存储 pgvector RLS │ └──────────────────────────────────────────┘