10 - 第八步:深度分析与记忆
普通报告只做「技术+消息+财报+期权 → LLM 综合 → 10 项」;深度模式 会在此基础上再跑「五类深度分析」、做「与上次对比」,并对综合评分做一次 LLM 微调,结果会写入持久化「记忆」供下次对比。本篇讲五类分析是什么、与上次对比怎么实现、以及记忆存在哪里、怎么用。
一、深度模式在整体里的位置
- 触发 :请求 Report 时传
deep=1,例如/report?deep=1&limit=5。 - 流程 :对每只股票不再只调
run_full_analysis,而是调run_one_ticker_deep_report(ticker),其内部会:- 先跑一次
run_full_analysis,得到「综合评分 + 10 项」的卡片基础。 - 再跑 五类深度分析(基本面深度、护城河、同行对比、空头视角、叙事变化),每类由 LangChain 链 + LLM 完成。
- 从 memory_store 取出该标的「上次」同类型分析(若有),做 与上次对比(大方向是否一致、近期趋势等)。
- 用五段深度摘要的短文 (每段截前约 200 字)再调一次 LLM,对当前综合评分做 微调 (输出「最终评分:N」或「调整:+1/0/-1」),更新卡片上的
score。 - 把五类摘要、对比结论、微调后的评分等写回卡片;同时把本次深度结果 写入 memory_store,供下次「与上次对比」用。
- 先跑一次
若未安装 LangChain 或链执行失败,深度块会显示「深度摘要未生成」或错误信息,但综合评分和普通卡片仍会保留。
二、五类深度分析分别是什么
- 基本面深度:收入与增长质量、盈利能力、现金流、商业模式、中长期风险等;基于财报与公司信息,由链里的 LLM 按模板输出。
- 护城河 :技术/切换成本/网络效应/规模/品牌等壁垒;Prompt 在
agents/prompts或chains/chains中。 - 同行对比:与若干同行在增速、盈利、估值等方面的差异;需要指定 peers(或默认一批),由链拉数据 + LLM 对比。
- 空头视角:增长可持续性、替代风险、估值风险、下跌触发点等;Prompt 引导模型从「看空」角度写。
- 叙事变化:财报与话术变化、市场叙事是否改变;基于近期信息由 LLM 概括。
每类分析的结果会存进 memory_store (按 ticker + analysis_type),并截取一段写入报告卡片的「深度」区块;同时取每段前约 200 字拼成短文,用于评分微调的那次 LLM 调用。
三、与上次对比怎么实现
- 数据来源 :
chains/memory_store。每次深度分析完成后,会把当次结果 append 到data/memory/memory_store.jsonl(或环境变量STOCK_AGENT_MEMORY_DIR指定目录)。 - 检索 :按
ticker+analysis_type(如fundamental_deep、moat、peers等)从 JSONL 里读最近 N 条(如 2 条),按时间倒序。 - 对比:把「上次」同类型分析的文本(或摘要)拼进 Prompt,让 LLM 回答「大方向是否一致、近期趋势如何」等,输出写入卡片的「与上次对比(大方向)」「近期对比趋势」等字段。
- 首次或无历史:若没有该标的该类型的往期记录,对比区块会显示「首次运行或尚无历史记录,再次运行 deep=1 后将显示与上次对比」之类提示。
也就是说:记忆是按「标的 + 分析类型」存的,不是按「用户会话」;对比是「同一只股票、同一类分析、上次 vs 这次」。
四、评分微调(_adjust_score_by_deep)
- 输入:当前综合评分(1~10)、五类深度分析的摘要(每段截前约 200 字)。
- Prompt:大意是「根据下面五段深度摘要,对当前评分做微调;只输出一行:要么『最终评分:N』(N 为 1~10 整数),要么『调整:+1 或 0 或 -1』」。
- 解析:若匹配到「最终评分:N」,则最终分 = clamp(N, 1, 10);若匹配到「调整:±1」,则最终分 = 原分 + 调整量再 clamp。
- 失败:若 LLM 未返回有效格式或调用异常,则保留原综合评分,不强制改分。
实现位置:agents/report_deep._adjust_score_by_deep;调用方在 run_one_ticker_deep_report 里,在五类深度和对比都跑完后执行。
五、memory_store 存什么、怎么用
- 存什么 :每行一条 JSON,包含
ticker、analysis_type、content(分析结果全文或序列化后的字符串)、ts(时间戳)。 - 写入 :由 LangChain 链在完成某类分析后调用
memory_store.save(ticker, analysis_type, content),追加到 JSONL 文件。 - 读取 :
memory_store.retrieve(ticker, analysis_type=None, last_n=2),按 ticker(和可选 analysis_type)取最近 last_n 条,用于「与上次对比」和上下文摘要。 - 存储目录 :默认
data/memory/;可通过环境变量STOCK_AGENT_MEMORY_DIR指定其它目录。
项目没有 用向量库或语义检索,记忆是「按 key(ticker + type)取最近几条」,不是「按相似问题检索」;若要做 RAG,可参考 docs/RAG文档建立与数据来源.md,把历史摘要等再做 embedding 存向量库。
六、小结与代码位置
- 深度入口 :
agents/report_deep.run_one_ticker_deep_report(ticker) - 五类链 :
chains/chains(如chain_fundamental_deep、chain_moat、chain_peers、chain_short、chain_narrative等),可由chain_full_deep或类似组合一次跑完;深度分析可配置为并行(DEEP_PARALLEL=1)以缩短耗时。 - 与上次对比 :
chains里调用memory_store.retrieve拿到上次结果,再调run_comparison或等价逻辑生成对比文本。 - 评分微调 :
agents/report_deep._adjust_score_by_deep - 记忆读写 :
chains/memory_store.save、retrieve
下一步:11 - 配置与扩展 ------ 环境变量、模型切换、RAG/OpenClaw 等扩展思路。
11 - 配置与扩展
本篇汇总常用配置方式(环境变量、模型与后端、报告行为),并简要说明如何扩展(RAG、OpenClaw/IM 等),方便按需调参和二次开发。
一、环境变量(常用)
| 变量 | 含义 | 默认 |
|---|---|---|
OLLAMA_MODEL |
Ollama 模型名 | qwen2.5:3b |
LLM_BACKEND |
后端:ollama / deepseek / openai | 无 key 时为 ollama |
DEEPSEEK_API_KEY |
DeepSeek API Key | --- |
OPENAI_API_KEY |
OpenAI API Key | --- |
LLM_TEMPERATURE |
采样温度,越低输出越稳定 | 0.3 |
LLM_MAX_TOKENS |
单次回复最大 token | 不设 |
LLM_TIMEOUT |
请求超时(秒) | 120 |
DEEP_PARALLEL |
深度分析是否并行,0=顺序 | 1 |
STOCK_AGENT_MEMORY_DIR |
记忆存储目录(JSONL) | 项目下 data/memory |
- 本地免费 :不设任何 API Key,默认用 Ollama;需先安装 Ollama 并拉取模型,例如
ollama pull qwen2.5:3b。 - 换模型 :
export OLLAMA_MODEL=qwen2.5:7b再启动;或设DEEPSEEK_API_KEY/OPENAI_API_KEY并设LLM_BACKEND=deepseek/openai。 - 调行为 :温度、max_tokens 等在
config/llm_config.py中可读环境变量,llm.ask_llm会使用这些默认值。
二、模型与后端(llm.py)
- Ollama :
base_url=http://localhost:11434/v1,无需 API Key;模型名由OLLAMA_MODEL控制。 - DeepSeek :设
DEEPSEEK_API_KEY,base_url=https://api.deepseek.com,常用模型如deepseek-chat。 - OpenAI :设
OPENAI_API_KEY,模型如gpt-4o-mini;若用第三方兼容 API,需在代码里改base_url。
选择逻辑:优先看 LLM_BACKEND;若未设则根据「已配置的 Key」推断(有 DeepSeek key 且未指定 ollama 则用 DeepSeek,以此类推)。
超时、连接错误、429/401 等会在 llm.py 里转成可读的 RuntimeError 提示(如「请先启动 Ollama」「API 配额不足」等)。
三、报告与 Prompt 可调点
- 综合 Prompt 的 10 项格式与说明 :在
agents/full_analysis._build_prompt里,可改角色描述、时间范围描述、以及 10 项的说明文字。 - 深度分析 Prompt 模板 :在
agents/prompts与chains/chains里,可改各类深度问题的表述。 - 报告 HTML 与筛选 :
report/build_html.py里可改标题样式、筛选项、排序选项、评分定性映射(_score_interpretation)等。 - 选股池与代码规范 :
config/tickers.py里可增删静态列表、改get_report_tickers逻辑(例如接动态接口)。
四、扩展方向(简要)
- RAG :把历史报告摘要、新闻摘要、财报解读等做成文档,切块后做 embedding 存向量库(如 Chroma);分析时按「标的/行业/问题」检索 TopK 再拼进 Prompt。思路与数据来源见
docs/RAG文档建立与数据来源.md。 - OpenClaw / iMessage :通过外部消息(如「帮我跑一份报告发到微信」)触发报告生成或推送;安装与接入步骤见
docs/OpenClaw安装与iMessage(imsg)接入.md、docs/OpenClaw集成说明.md。 - 更多数据源:研报、公告、宏观数据等需自行对接 API 或爬虫;可在对应 agent(如 news、fundamental)或新建模块中拉取,再拼进 Prompt 或单独展示。
- 多轮对话记忆 :当前记忆是「按标的+分析类型」的 JSONL,不是「按用户会话」的对话历史;若要「连续问答」形态,可在此基础上加 LangChain 的
ConversationBufferWindowMemory等,与现有 memory_store 并存。
五、小结
- 配置 :环境变量控制模型、后端、超时、温度、深度是否并行、记忆目录;
config/llm_config与llm.py是入口。 - 扩展:RAG、OpenClaw、新数据源、对话记忆等都有文档或代码入口可循;按需选一块先做最小可行再迭代。
本系列博客到这里告一段落;若你希望某一块再拆成「更细的步骤」或「带代码片段」,可以指定章节再补一篇。