之前在业务迭代中,经常遇到一个很头疼的问题:AI 每次给出的方案好像都“忘了”昨天刚确认过的结论。产品经理说“这个需求上周不是已经讨论过不做吗”,AI 却一本正经地给出完全反向的建议。后来我在调研决策类 Agent 落地时,注意到一种叫 DeepSeek Harness 的思路——它本质上不是某个神秘框架,而是把“模型调用”外面再包一层决策 harness,让每一次 AI 的关键判断都能被记录、被检索、被回放到下一次上下文里。这篇文章就把这套方法拆开,结合实际项目讲清楚怎么让 AI 真正“记住”历史决策。
如果你是正在做 AI 客服、智能助手、自动化决策系统,或者只是被“AI 没有长期记忆”折磨过的开发者,这篇内容都适用。读完你会掌握:决策数据的结构化设计、历史上下文的注入方式、一个可运行的项目示例,以及常见坑位的排查思路。
1. 让 AI 记住历史决策,到底难在哪
1.1 大模型的“记忆”本质是上下文
先看一个最基础的结论:像 DeepSeek 这类大模型本身是没有持久记忆的。每次调用 API,它看到的只有你这一次请求携带的 messages。之前聊过什么、拍板过什么,模型一概不知道。它能把对话续上,是因为你把历史记录重新传给了它;一旦这些历史没有被保存,模型就会“失忆”。
所以“让 AI 记住历史决策”这个问题,本质上不是模型能力问题,而是工程问题。你需要自己在外部维护一套记忆系统,在合适的时候把历史决策压缩、筛选、注入到模型上下文里。
1.2 普通对话记录为什么不够用
很多人第一反应是:把聊天记录全部存下来,下次全量传给模型不就行了?听起来简单,但实际会踩几个坑:
第一,上下文窗口有限。哪怕现在模型支持 128K 甚至更大,也扛不住长期多轮对话的无脑堆叠,很快会超限,而且成本急剧上升。
第二,全量历史里充满噪音。日常对话里大量内容是寒暄、确认过程、临时数据,真正“拍板”的决策点可能只有 20%。把这些噪音全部喂给模型,反而会干扰判断。
第三,缺少结构性。决策往往是“在什么背景下,基于什么依据,选了什么方案,放弃了什么方案”。普通聊天记录里这些信息是散落的,模型很难在下次决策时精准复用。
1.3 DeepSeek Harness 方法的核心
DeepSeek Harness 给我的启发是:不要把所有历史交互都交给模型自己理解,而是用一层 harness 把决策这个过程显式地“钳制”住。具体来说,它把每次决策拆成几个固定的字段,比如决策编号、触发场景、可选方案、决策结论、原因、影响、后续状态。然后把这些字段持久化到数据库中。下一次需要决策时,harness 先查询相关的历史决策,生成一份“决策摘要”注入到系统提示词里。
这样一来,AI 看到的不是一堆聊天记录,而是一份类似“项目决策记录”的结构化记忆。模型能快速理解:过去在哪些约束下做过什么选择,结果如何,哪些条件变了需要重新决策。
我理解这个方法的核心价值在于:把“记忆”从模型的隐状态里解放出来,变成显式的、可查询、可审计的工程资产。这不仅解决了记忆问题,还让整个 AI 决策过程变得可追溯、可回放、可复盘。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与整体方案设计
以下示例以 Python 3.9+ 为基础,数据库使用 SQLite——它轻量、零配置,适合演示和中小项目起步。大模型接口我们按 OpenAI 兼容接口来写,DeepSeek 的调用方式也遵循这个协议,但代码不绑定具体厂商,只要你的模型服务支持 chat/completions 接口,都能适配。
项目目录建议这样组织:
code复制ai-decision-harness/
├── main.py # 入口,跑一个完整示例
├── decision_store.py # 决策存储层,负责读写 SQLite
├── llm_client.py # 模型调用层,封装 chat/completions
├── prompts.py # 提示词模板
├── decisions.db # SQLite 数据库,首次运行自动创建
└── requirements.txt # 依赖清单
依赖只需要一个 openai Python 包,用来调用兼容接口:
bash复制pip install openai
版本需要根据你的实际环境调整,比如 openai>=1.0.0。如果你不使用 SDK,也可以用 requests 直接调用 HTTP 接口,属于具体情况具体分析。
需要强调:本文的代码重点在于演示“决策记忆”的工程思路,模型返回的内容可能因版本、服务商不同而存在差异,建议你跑通以后再接入自己的业务数据。
3. 核心原理拆解:决策日志、上下文注入、回放
3.1 决策日志:把一次判断变成一条记录
想记住决策,首先要定义“决策长什么样”。我建议至少包含以下字段:
decision_id:全局唯一,方便回溯。scene:决策场景,用来筛选相关历史。比如“需求优先级评审”“技术方案选型”“故障处理”。context:做决策时的背景信息。可以是一段文本,也可以是结构化 JSON。options:当前有哪些可选方案。conclusion:最终选了哪个方案,或者结论是什么。reason:为什么选这个,放弃其他方案的理由。status:决策状态,比如active、superseded、executed。created_at:决策时间。
把这些字段存入一张表,相当于给 AI 建立了一本“决策日记”。写日志这一步必须在模型返回结论后立刻执行,因为决策过程是不可重来的,错过就没有了。
3.2 上下文注入:只带“相关决策”而不是全量历史
当模型需要做新决策时,我们要从库里捞出一批历史决策。这里有两个关键点:
第一是筛选。根据当前场景和关键词,只选出与该决策相关的记录。比如现在要评审新需求,就只查 scene='需求优先级评审' 的记录,最多再补一些同类型的相似决策。
第二是压缩。找到的历史记录可能还是很多,需要转成摘要。最简单的做法是只保留“结论 + 原因 + 状态”,并且传给模型时加上“以下是从前决策记录中提取的历史摘要,仅供参考,如果当前条件发生变化可以推翻旧结论”的提示。这样可以避免模型把历史决策当成不可变更的教条。
注入位置建议放在系统提示词里,或者作为第一条用户消息的前缀。不要放在最后,否则模型可能忽略较早的内容,也可能被新内容淹没。
3.3 回放与追溯:让每次决策有据可查
Harness 方法还有一个容易被忽略的价值:回放。当 AI 给了一个建议,你可以反查“它参考了哪些历史决策”,甚至把当时的上下文重新拼接出来,看看旧决策是否合理。这个能力在项目复盘、事故排查、合规审计里非常有用。
回放不需要复杂算法。只要在生成决策时,记录本次参考了哪些 decision_id,然后通过 id 拉取完整记录即可。这个字段我通常叫 ref_decision_ids,用 JSON 数组存储。
4. 实战:做一个带历史决策记忆的需求评审助手
下面我们做一个具体的小系统:“需求优先级评审助手”。用户每次提一个新需求,系统先检索历史决策,再调用大模型给出优先级建议,最后把这条建议连同用户的反馈存成新决策。代码可以完整运行。
4.1 配置模型调用客户端
文件路径:llm_client.py
python复制from openai import OpenAI
client = OpenAI(
api_key="你的API密钥",
base_url="https://api.deepseek.com/v1"
)
def chat(messages, temperature=0.3):
resp = client.chat.completions.create(
model="deepseek-chat",
messages=messages,
temperature=temperature
)
return resp.choices[0].message.content
这里需要特别注意:base_url 和 model 必须以你的服务商文档为准,上述只是示例。千万不要把真实密钥提交到公共仓库。如果你用的是私有化部署模型,base_url 换成你内网网关地址即可。
4.2 实现决策存储层
文件路径:decision_store.py
这段代码负责建表、插入决策、按场景查询历史决策。
python复制import sqlite3
import json
from datetime import datetime
DB_PATH = "decisions.db"
def get_conn():
conn = sqlite3.connect(DB_PATH)
conn.row_factory = sqlite3.Row
return conn
def init_db():
with get_conn() as conn:
conn.execute("""
CREATE TABLE IF NOT EXISTS decisions (
decision_id TEXT PRIMARY KEY,
scene TEXT NOT NULL,
context TEXT,
options TEXT,
conclusion TEXT,
reason TEXT,
status TEXT DEFAULT 'active',
ref_decision_ids TEXT,
created_at TEXT
)
""")
conn.execute("""
CREATE INDEX IF NOT EXISTS idx_decisions_scene
ON decisions(scene)
""")
def save_decision(decision: dict):
with get_conn() as conn:
conn.execute(
"INSERT OR REPLACE INTO decisions VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
(
decision["decision_id"],
decision["scene"],
decision.get("context", ""),
json.dumps(decision.get("options", []), ensure_ascii=False),
decision.get("conclusion", ""),
decision.get("reason", ""),
decision.get("status", "active"),
json.dumps(decision.get("ref_decision_ids", []), ensure_ascii=False),
decision.get("created_at", datetime.now().isoformat())
)
)
def query_history(scene: str, limit: int = 10):
with get_conn() as conn:
rows = conn.execute(
"SELECT * FROM decisions WHERE scene = ? ORDER BY created_at DESC LIMIT ?",
(scene, limit)
).fetchall()
return [dict(row) for row in rows]
def get_decision(decision_id: str):
with get_conn() as conn:
row = conn.execute(
"SELECT * FROM decisions WHERE decision_id = ?",
(decision_id,)
).fetchone()
return dict(row) if row else None
这段代码里有几个设计点值得说明:
- 用
INSERT OR REPLACE,便于重复跑示例时覆盖同一条决策。 options和ref_decision_ids存成 JSON 字符串,读取时再json.loads。这样能保持数据结构完整性,也方便以后迁移到 PostgreSQL 的 JSON 字段。- 查询只按
scene过滤,因为示例场景简单。真实项目建议再加关键词匹配或向量检索。
4.3 构建历史摘要和提示词
文件路径:prompts.py
这里要定义把历史记录转成摘要的模板。核心原则是:控制长度,保留关键信息,并明确告诉模型“历史决策可以被新条件推翻”。
python复制def build_history_summary(history_records: list) -> str:
if not history_records:
return "暂无历史决策记录。"
lines = []
for i, rec in enumerate(history_records, 1):
options = rec["options"]
if options:
options = ", ".join(json.loads(options))
else:
options = "无"
lines.append(
f"{i}. 决策ID: {rec['decision_id']}"
f" | 结论: {rec['conclusion']}"
f" | 原因: {rec['reason']}"
f" | 已放弃方案: {options}"
f" | 状态: {rec['status']}"
)
return "\n".join(lines)
def build_system_prompt(history_summary: str):
return f"""你是一名资深产品和技术顾问,负责评估新需求的优先级。
请参考下面的历史决策记录,但注意:历史决策反映的是过去的背景和约束。
如果当前需求与历史记录的前提条件不同,你可以做出不同的判断。
历史决策记录:
{history_summary}
请按以下结构输出,不要输出额外解释:
优先级: 高/中/低
理由: 不超过120字
建议方案: 最多3条,用分号分隔
"""
注意 build_system_prompt 里没有直接拼接新需求,因为它属于用户输入,应该放在用户消息里,避免和系统指令混淆。
4.4 主流程:检索历史、调用模型、存储新决策
文件路径:main.py
python复制import uuid
from datetime import datetime
from decision_store import init_db, save_decision, query_history
from llm_client import chat
from prompts import build_history_summary, build_system_prompt
def review_requirement(requirement: str):
init_db()
# 场景设定
scene = "需求优先级评审"
# 1. 检索历史决策
history = query_history(scene, limit=5)
history_summary = build_history_summary(history)
system_prompt = build_system_prompt(history_summary)
# 2. 调用模型
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": f"新需求如下:{requirement}"}
]
result = chat(messages)
# 3. 把模型输出转成决策记录
decision = {
"decision_id": uuid.uuid4().hex,
"scene": scene,
"context": requirement,
"options": ["高优先级", "中优先级", "低优先级"],
"conclusion": parse_conclusion(result),
"reason": parse_reason(result),
"status": "active",
"ref_decision_ids": [rec["decision_id"] for rec in history],
"created_at": datetime.now().isoformat()
}
save_decision(decision)
print("本次决策已记录。")
print(result)
return decision
def parse_conclusion(result: str) -> str:
for line in result.splitlines():
if line.startswith("优先级:"):
return line.split(":", 1)[1].strip()
return result[:30]
def parse_reason(result: str) -> str:
for line in result.splitlines():
if line.startswith("理由:"):
return line.split(":", 1)[1].strip()
return ""
if __name__ == "__main__":
# 第一次决策
review_requirement("上线一个用户积分兑换页面,用于提高老用户活跃度")
# 第二次相同场景决策,AI 会看到第一条记录
review_requirement("开发一个用户等级体系,需要评估是否比积分兑换页面优先")
这里有两个值得注意的点:
parse_conclusion和parse_reason是简单的行解析。如果模型输出格式不稳定,建议用 JSON 模式或函数调用(function calling)来保证结构化返回,避免解析失败。- 第二次输入时,代码会从数据库里查到第一次的决策,并作为摘要注入系统提示词。这就是“记住历史决策”的体现。
4.5 运行与验证
在命令行执行:
bash复制python main.py
预期输出类似:
code复制本次决策已记录。
优先级: 中
理由: 积分兑换属于运营活动,能短期提升活跃度,但复杂度不高,建议在核心链路稳定后快速上线。
建议方案: 先做简化版;配合用户分群触达;上线后观察7日留存。
本次决策已记录。
优先级: 高
理由: 历史决策中积分兑换尚未实施,用户等级体系是长期激励框架,且与积分体系可结合,建议优先规划,避免重复建设。
你可以用一个简单的 SQL 去检查数据库里的记录:
bash复制sqlite3 decisions.db "select decision_id, scene, conclusion, reason, ref_decision_ids from decisions;"
这时会发现第二次决策的 ref_decision_ids 里放着第一次的 decision_id,证明 AI 在生成第二次建议时确实参考了历史决策。
5. 常见问题与排查思路
我在实际跑这类方案时,遇到过不少问题。下面整理成表,方便你直接对照排查。
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
| 模型好像没记住历史决策 | 历史摘要没注入到请求里,或者注入位置靠后 | 检查 system 消息内容,确认历史记录出现在模型返回前 |
| 注入历史后回答质量反而变差 | 历史记录过多、格式串行、噪声太大 | 缩小 limit,只保留最重要字段,必要时用向量检索替代简单固定查询 |
| 模型输出的结论解析失败 | 输出格式不稳定,用普通文本解析不可靠 | 改用 JSON 输出模式,或使用工具调用,让模型按固定结构返回 |
| 决策库越积越大,查询越来越慢 | SQLite 单表存储,缺少索引和归档 | 给 scene 和 created_at 建联合索引,定期归档旧数据到冷存储 |
| 多用户共用一套决策库,互相干扰 | 缺少用户或项目维度 | 数据表增加 owner_id 字段,查询时必须带该字段 |
| 历史决策里的敏感信息被注入到模型 | 未脱敏直接入库再查询 | 在入库前做脱敏处理,比如把手机号、身份证替换为占位符,或限制字段级别存储 |
最常见的排查顺序是:先打印出实际传给模型的 system 消息,看看历史摘要是否真的存在。很多时候问题不是模型没记住,而是你的 prompt 里根本没有带上记忆。
6. 工程最佳实践与生产落地建议
6.1 从 SQLite 升级到专用存储
本文示例用 SQLite 是为了让你最快跑通。生产环境建议换成 PostgreSQL。它天然支持 JSONB,可以做 scene + owner_id 联合索引,还能用 tsvector 做全文检索。如果规模再大,可以把决策向量化后用向量数据库做相似度召回,让 AI 不只靠场景查询,还能根据语义找到历史相似决策。
不过升级的前提是先把“决策记录写入”和“历史查询”封装成接口,而不是让业务代码到处写 SQL。这样以后换存储层,改一个实现类就行。
6.2 决策记录必须带“版本”概念
历史决策不是永远正确。当你发现某条决策过时,不要直接删掉它,推荐把状态改成 superseded,同时新建一条新决策,并在新决策里记录它替代了哪条旧决策。这样既保留完整的历史轨迹,又避免 AI 反复参考已被推翻的结论。
实现上可以在 save_decision 里增加一个逻辑:更新旧记录状态为 superseded,写入新记录。这是除了记忆之外,另一个对 AI 决策质量很有帮助的工程细节。
6.3 控制上下文开销,设置预算熔断
每次注入的历史记录越多,token 成本越高。建议限制注入条数,比如最多 20 条;如果某条历史决策的记录特别长,可以只取 conclusion 和 reason,不取完整 context。还可以为每次请求做一个 token 计数器,如果摘要超过设定阈值,用摘要的摘要来压缩,或者丢弃最早的历史。
在团队协作中,更应该为每个调用设置预算熔断。如果某次请求连续失败,不应该无限重试,而是记录失败后的降级逻辑——比如不调用模型、返回默认建议,同时保留现场信息。
6.4 权限隔离与安全边界
如果你的系统服务多个业务方,决策库必须做 data isolation。每个用户或项目只能查询自己的历史决策,否则一个用户的数据会泄漏给另一个用户。最简单的实现是在所有查询条件里强制带 owner_id,并通过后端服务统一注入,而不是信任前端传参。
同时要考虑:决策记录里可能包含未公开的商业模式、价格策略等敏感信息。入库前可以做字段级的白名单过滤,只存必要的上下文。在把历史决策注入模型之前,再做一次脱敏处理,避免敏感数据外泄。
6.5 用审计日志支撑复盘
几个星期后你可能会问:某条决策当初为什么那么定?此时只有 conclusion 和 reason 还不够,最好还要有完整的原始快照,包括当时的用户输入、模型返回、历史摘要、以及最终人工是否采纳。
建议为每条决策增加一个 snapshot 字段,存放完整的 messages 数组,但这是个高成本字段,要限制保存条数。也可以把这部分内容落到对象存储或日志平台,只保留链接在数据库里。这样既保证可追溯,又不会让决策库变得臃肿。
7. 这套方法还能怎么延伸
如果你已经跑通了上面的示例,下一步可以尝试加入三个能力。
一是人工反馈回路。模型给出的决策不一定被采纳,增加一个“是否采纳”字段,用人工确认结果修正历史记录。比如模型建议“高优先级”,但产品经理决定“低优先级”,那么这条人工修正后的结论比模型原始输出更有价值。下次再把历史注入模型时,应该告诉模型“用户最终采纳的是低优先级”,而不是只看模型自己的建议。
二是相似度检索。把 context 和 conclusion 组合成向量,用向量数据库检索 Top-K 相似决策。这样即使场景描述不完全一致,AI 也能找到“上次类似情况下是怎么处理的”。
三是决策指标评估。为每条决策绑定后续指标,比如“按高优先级处理后,用户活跃度提升了多少”。把结果反馈给模型,模型就能在下次决策时更好地判断哪种优先级策略真正有效。这就不是简单的记忆了,而是形成了“决策-执行-反馈”的自我进化闭环。
这些延伸方向,本质上还是围绕 Harness 方法的核心:把 AI 决策变成可记录的工程实体,而不是每次从零开始的“灵光一闪”。掌握了这个思路,你不仅能解决“让 AI 记住历史决策”的问题,还能让 AI 在复杂业务中越来越像真正的团队成员。
