
2. **数据隐私**:量化策略、持仓信息、回测代码都属于核心资产,一旦交给云端 LLM 处理,就存在向第三方泄露的风险。
3. **调用成本**:高频执行“数据查询 分析判断”类任务时,如果全部走云端 LLM,每个任务可能花费 0.5-2 美元,长期累计下来成本非常可观。本地化部署可以从根本上解决这三个问题:本地 LLM(如 Qwen2.5-72B、DeepSeek-V3)响应通常可控制在 1-2 秒内,本地数据访问是毫秒级,本地模型推理的边际调用成本几乎可以忽略。## 二、整体架构整个 Agent 一共分为 5 层:```┌─────────────────────────────────────┐
│交互层(CLI / Web UI)│├─────────────────────────────────────┤
│Agent 编排层(任务规划 工具调用)│├─────────────────────────────────────┤
│工具层(数据查询 回测 可视化) │├─────────────────────────────────────┤
│数据层(本地股票数据引擎) │├─────────────────────────────────────┤
│基础设施层(本地 LLM 向量库) │└─────────────────────────────────────┘
```每一层我都尽量采用轻量化方案,但要求是必须能稳定跑通完整的“研究 → 分析 → 回测”全流程。## 三、基础设施层基础设施层主要由两个核心组件组成:**本地 LLM** 和 **向量数据库**。**本地 LLM** 我使用的是 Qwen2.5-72B-Instruct,部署在 RTX 4090 上。模型参数规模为 72B,经过 4-bit 量化后大约占用 40GB 显存,单张 4090 的 24GB 显存放不下,因此我采用了双 4090 部署方案。推理速度大约在 15 tokens/秒,基本能够满足“边思考边输出”的使用需求。向量库使用的是 ChromaDB,本地部署,主要用于存储“研究笔记”和“历史回测结果”,便于 Agent 检索过往经验、复用已有研究结论。## 四、数据层数据层我采用的是本地股票数据引擎,把 A 股 5000 多只股票对应的 200 多个数据集全部沉淀到本地。所有数据统一通过 HTTP 接口访问(这是 ig50 的设计,本地运行了一个 HTTP 服务),能够实现毫秒级响应。Agent 用到的核心接口包括:- 股票列表:`base/gplist`,返回 A 股全部股票代码与名称- 实时行情:`time/real/{dm}`,获取单只股票的实时快照
- 历史 K 线:`time/history/trade/{dm}/{level}`,支持从 1 分钟线到月线的全级别数据- 财务数据:`time/f10/fi/{dm}`,三大财务报表完整可用
- 资金流向:`time/zijin/zlzjzs/{dm}`,查看主力净流入- 龙虎榜:`time/data/longhubang`,获取上榜席位数据
- 行业资金流向:`all/zjlx/zjhhy`,查看行业资金排行- 逐笔成交:`time/real/trace/onebyone/{dm}`,返回每笔成交明细
- 十档盘口:`time/real/trace/level10/{dm}`,获取十档行情数据- L2 指标:`time/real/trace/l2sign/{dm}`,包括 DDX、DDY、撤单比率等指标
这些接口基本覆盖了量化研究 95% 以上的常见场景。
五、工具层
工具层的作用,是把底层数据接口封装成 Agent 可以直接调用的“工具”。每个工具本质上都是一个 Python 函数,并通过文档字符串明确说明输入参数和输出格式。
下面举几个核心工具的例子:
**工具 1:query_stock_basic**
```python
def query_stock_basic(keyword: str) -> dict:"""根据关键词(股票代码或股票名称)查询股票基本信息。
返回: dict, 包含 dm(代码), mc(名称), 行业, 上市日期 等字段"""
# 调用 ig50 base/gplist 接口stocks = ig50_get('base/gplist')
for s in stocks:if keyword in s['dm'] or keyword in s['mc']:
return sreturn None
```**工具 2:get_realtime_quote**```pythondef get_realtime_quote(dm: str) -> dict:
"""获取股票实时行情数据。参数 dm: 股票代码,如 '000001'
返回: dict, 包含 cjsj, cjjg, cjl, zf(涨幅) 等字段"""
return ig50_get(f'time/real/{dm}')```
**工具 3:get_history_kline**
```python
def get_history_kline(dm: str, level: str, days: int) -> list:"""获取股票历史 K 线数据。
参数 dm: 股票代码参数 level: K 线级别,如 '1m', '5m', '30m', '1d'
参数 days: 获取天数返回: list, 每个元素包含 rq, open, high, low, close, volume
"""直接调用 return ig50_get(f'time/history/trade/{dm}/{level}')[-days:],取回对应交易历史后,再截取最近 days 条记录。
```**工具 4:get_money_flow**```pythondef get_money_flow(dm: str) -> dict:
"""获取股票资金流向数据。参数 dm: 股票代码
返回: dict, 包含 zlJlr(主力净流入), shJlr(散户净流入), zlJlb(主力净比) 等字段"""
return ig50_get(f'time/zijin/zlzjzs/{dm}')```
**工具 5:run_backtest**
```python
def run_backtest(strategy_code: str, dm: str, start_date: str, end_date: str) -> dict:"""运行策略回测。
参数 strategy_code: 策略代码(Python 函数)参数 dm: 股票代码
参数 start_date, end_date: 回测时间范围返回: dict, 包含 年化收益, 最大回撤, 夏普比率, 胜率
"""# 实际实现比较复杂,这里只展示接口
...```
工具层总共封装了 20 多个工具,覆盖数据查询、量化回测、可视化分析三大类能力。
六、Agent 编排层
Agent 编排层才是整套系统中最关键的部分。这里我采用的是 ReAct 框架(Reasoning Acting),让 LLM 可以自主拆解任务、调度工具,并在获得结果后继续回看、修正和补充分析。
具体来说,当 Agent 接收到用户问题后,会按照以下循环执行:
1. **思考(Thought)**:分析当前问题,判断下一步应该做什么
2. **行动(Action)**:调用合适的工具3. **观察(Observation)**:接收工具返回结果
4. **反思(Reflection)**:检查当前结果是否足以回答问题,并决定是否继续下一轮举一个真实示例。用户提问是:“帮我分析一下宁德时代最近一周的资金流向,看看主力是在建仓还是出货。”Agent 的推理流程大致如下:```Thought: 用户想了解宁德时代最近一周的资金流向,并判断主力意图。
我需要先获取宁德时代的股票代码,然后用 get_money_flow 工具拉取相关数据。Action: 调用 query_stock_basic("宁德时代")Observation: {"dm": "300750", "mc": "宁德时代", ...}
Thought: 已经拿到股票代码。现在调用 get_money_flow 获取资金流向数据。
Action: 调用 get_money_flow("300750")
Observation: {"zlJlr": 850000000, "shJlr": -230000000, ...}Thought: 单日资金数据可能不够准确,需要结合最近 7 天走势一起分析。Action: 调用 get_history_kline("300750", "1d", 7)Observation: [...7 天的 K 线数据...]
Thought: 结合资金流向和 K 线走势综合判断。主力净流入 8.5 亿,散户净流出 2.3 亿,
且股价近 7 天小幅上涨 3.2%,符合“主力建仓”特征。Final Answer: 宁德时代最近一周主力净流入 8.5 亿,结合股价温和上涨 3.2%,判断主力当前更偏向于建仓阶段。
```整个流程大约需要 8-10 轮 LLM 调用 工具调用,总耗时通常在 5-15 秒之间(具体取决于数据量大小)。## 七、关键设计决策**决策 1:工具调用采用结构化输出**LLM 在调用工具时,必须输出严格的 JSON(包含 tool_name 和 arguments)。我使用 Pydantic 定义工具 schema,强制 LLM 按照 schema 生成结果。这个看似简单的设计,让“工具调用失败率”从 30% 降低到了 5%。**决策 2:工具执行结果做“摘要压缩”**LLM 的上下文窗口是有限的(Qwen2.5-72B 为 32K)。如果工具返回的数据量过大,比如返回 1 年的逐笔成交数据,就很容易撑爆上下文。因此我增加了一个“结果摘要”模块,自动把大体量结果提炼成关键统计信息(均值、最大值、最小值、趋势),再交给 LLM 继续推理。**决策 3:Agent 状态通过对话历史管理**Agent 的“思考链路”会随着轮次增加而不断变长,超过 10 轮后通常就会开始混乱。我采用“对话历史摘要”的方式,定期把前几轮交互压缩成 1-2 段摘要,再重新喂给 LLM,从而保持上下文紧凑且可控。**决策 4:本地 LLM 的 Prompt 工程必须更细**本地 LLM(Qwen2.5-72B)在指令遵循能力上相比 GPT-4 略弱,因此需要更详细、更明确的 Prompt 设计。我把每个工具的“使用说明 调用示例”都写入 system prompt 中,最终把工具调用成功率从 60% 提升到了 90%。## 八、踩过的坑**坑 1:本地 LLM 的“幻觉”问题**本地 LLM 在部分场景下会出现“幻觉”,例如调用不存在的工具名、编造不存在的数据字段名。为了解决这个问题,我加了一层“工具白名单”机制,LLM 只能调用已注册的工具,否则直接报错。**坑 2:数据查询的“超时”问题**某些复杂查询任务(例如一次性拉取 5000 只股票的全量财务数据)很容易超时。我加入了“分批查询 进度反馈”机制,让 Agent 在执行长任务时可以实时展示处理进度。**坑 3:策略代码的安全执行**用户可能会要求 Agent “运行这段策略代码”,但如果直接 exec 用户提交的代码,就会带来明显的安全风险。因此我使用了一个“受限执行环境”,只允许访问预定义的数据接口和回测接口,禁止文件系统访问与网络访问。**坑 4:回测结果的“过度拟合”提示**LLM 在分析回测结果时,往往倾向于“美化”策略表现。为此我增加了一个“回测警示”模块,自动识别“过拟合特征”(例如参数过于复杂、样本内表现显著好于样本外),并在最终输出中附带风险提示。## 九、效果这套 Agent 已经稳定运行了大半年,最大的几个实际发现如下:1. **80% 的量化研究任务可以由 Agent 自主完成**:包括数据查询、基础分析、回测执行,几乎不再需要人工频繁介入。2. **复杂策略开发仍然需要人工参与**:例如策略思路、因子设计、风控规则等核心环节,依然需要人的判断,Agent 更适合做“辅助实现”和“执行加速”。
3. **本地化部署的低延迟优势非常明显**:从“提出问题”到“获得可用研究结果”,平均可以在 30 秒内完成,而云端方案通常至少需要 2-3 分钟。最关键的是,本地化让“研究迭代速度”显著提升。以前调试一个因子,可能要等待 5 分钟的云端 API 返回;现在大约 30 秒就能拿到结果,整体调试效率提升了 10 倍。## 十、最后说几句Agent 框架最大的价值,不是“替代人”,而是“让人把更多时间用在判断和决策上”。过去做量化研究时,60% 的时间往往花在“查数据 写脚本 跑回测”这些执行环节上,只有 40% 的时间真正用于“思考策略”。而本地化 Agent 的意义,就是把这个比例反过来——80% 的时间思考策略,20% 的时间处理执行细节。如果你也在做量化研究,建议优先从“数据查询 Agent”开始——先把数据接口封装成工具,让 LLM 具备自主查询能力,这是当前 ROI 最高、落地也最快的切入点。随后再逐步扩展到“分析 Agent”和“回测 Agent”,最后再尝试“策略生成 Agent”。完整代码和工具集展开会很长,核心思路其实就是这样——本地 LLM 本地数据 ReAct 编排。资料参考:ig50","createTime":1786069756,"ext":{"closeTextLink":0,"comment_ban":1,"description":"","focusRead":0},"fa vNum":0,"html":"","isOriginal":0,"likeNum":0,