ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

大模型本地部署实战:用Python和提示词工程搭建股票AI分析系统

大模型本地部署实战:用Python和提示词工程搭建股票AI分析系统 最近在梳理大模型落地方案时常被问到一句话“大模型除了聊天还能不能干点正事”其实能干的场景很多其中一个很适合练手、又能串联大模型部署、AI 编程、数据分析和 Web 服务的项目就是“专属股票分析系统”。这篇文章会围绕“大模型 股票分析”这个主题从零搭建一套本地可运行的股票分析小系统。我们会先把系统拆解清楚再完成本地大模型部署接着用 Python 抓取股票数据最后通过提示词工程让大模型输出结构化的分析报告。整个流程会尽量贴近真实工程代码可以直接复制能跑通也方便你继续扩展。本文适合以下几类读者想学习大模型本地部署和 API 调用的开发者。想用 Python 构建数据分析工具但不想只做数据展示的读者。对 AI 编程感兴趣的开发者可以对照本文流程理解“AI 辅助编码”的思想。想给股票分析加一层“AI 解读”能力的量化爱好者。需要提前说明的是本文是技术教程不是投资建议。最终系统输出的内容只能作为技术研究参考不应直接作为交易决策依据。1. 背景与核心概念1.1 为什么用大模型做股票分析传统股票分析通常分两步第一步是拿到行情数据第二步是根据指标计算或走势图做判断。人工分析消耗时间机械规则又缺少对新闻、公告、市场情绪的解读能力。大模型的出现恰好补上了“数据到结论”之间的解读环节。我们可以让大模型完成这样几件事对给定股票的近期行情数据做摘要。从技术指标层面判断趋势状态。结合市盈率、市净率等基本面指标输出多维度分析。按固定格式生成包含“今日观点、关键指标、风险提示”的分析简报。这些事情并不需要模型有“实时交易能力”只需要我们提供结构化数据并设计好提示词。因此这是一个非常适合演示大模型工程化能力的场景。1.2 FDE 与大模型部署的关系FDE 这个词在最近讨论里出现频率很高。目前它并没有一个完全统一的官方定义常见理解有两类一类是“Fast Development Engineer”可以理解为“快速开发工程师”核心是利用 AI 编程工具和自动化方式提升开发效率。另一类是偏“前端开发”方向的称呼在一些团队中也叫 Framework Developer Engineer。在本文中我们不纠结哪个定义更“正统”。重点是把 FDE 体现出来的工程思维用于项目落地理解需求、拆分任务、用大模型辅助开发与部署、最后形成可运行系统。换句话说FDE 工程师的职责并不是“会写提示词就行”而是要掌握如何把大模型集成进真实业务包括环境配置、接口调用、提示词设计、异常处理和部署上线。本文的股票分析系统就是一个典型的 FDE 实战练习。1.3 系统技术选型为了让项目尽量简单同时保留真实工程结构我选择了以下技术栈模块技术选型说明本地大模型Ollama 开源模型不需要 GPU 也能跑量化小模型大模型接口OpenAI 兼容接口方便替换为云端模型数据获取AKShare免费开源财经数据接口后端服务FastAPI轻量级 Web 服务前端页面HTML 原生 JavaScript减少依赖便于演示AI 编程辅助Cursor 等 AI 编辑器加快编码效率非必需这个选型的好处是所有组件都可以本地安装不依赖商业密钥数据源免费模型可切换。如果后续希望升级为 GPT 或国内大模型 API只需要改一行 base_url。2. 整体方案设计先看系统的整体工作流程。这部分很重要决定了我们后续代码怎么写。2.1 业务流程拆解整个股票分析系统可以拆成 4 层数据层通过 AKShare 获取股票实时行情、历史行情和基本面数据。服务层FastAPI 提供两个接口一个用于查询原始数据一个用于返回 AI 分析报告。模型层Ollama 本地部署大模型通过 OpenAI 兼容接口提供服务。展示层浏览器页面输入股票代码点击按钮后显示分析结果。流程如下用户输入股票代码 ↓ FastAPI 接收请求 ↓ Python 调用 AKShare 获取行情与基本面数据 ↓ 组装提示词含结构化数据 ↓ 请求本地大模型接口 ↓ 大模型返回分析报告 ↓ 前端页面展示结果2.2 为什么选择 Ollama 本地部署本地部署大模型在 2025 年已经不是新鲜事但很多新手会卡在“模型下载慢、显存不够、不知道怎么调用 API”上。Ollama 把这三件事都简化了。一条命令即可安装。一条命令即可下载并启动模型。支持 OpenAI 兼容 API直接使用 requests 或 openai 库调用。更重要的是本地部署能避免把股票数据发送到外部服务这对金融数据合规场景有天然优势。虽然本地小模型的分析能力不如云端大模型但胜在免费、私密、可定制。2.3 模型选择的建议考虑到多数读者的个人电脑没有独立 GPU本文示例以量化版本模型为例配置。常见的可选模型如下通义千问 Qwen2.5 7B 系列中文理解好适合分析中文新闻和股票名称。Llama 3.1 8B 系列英文能力强中文稍弱。Phi-3 Mini体积小跑得快适合低配置机器。如果你的电脑显存充足可以选用更大参数模型如果在纯 CPU 环境建议选择 3B 或 7B 的量化版本。版本需要根据你的机器情况调整本文重点演示配置思路不必追求超大模型。3. 环境准备与安装3.1 基础环境要求建议环境如下操作系统Windows 10/11、macOS、Linux 均可。Python 版本3.10 或 3.11。内存至少 8GB16GB 以上更好。磁盘空间至少 10GB 空闲空间用于存放模型文件。可选NVIDIA GPU 显卡显存 6GB 以上可流畅运行 7B 量化模型。不需要 GPU纯 CPU 也能运行只是推理速度会慢一些。3.2 安装 Python 依赖先创建项目目录并初始化 Python 虚拟环境。mkdir stock-ai-analysis cd stock-ai-analysis python -m venv venv # Windows venv\Scripts\activate # macOS / Linux source venv/bin/activate接着安装依赖库pip install fastapi uvicorn akshare pandas openai python-dotenv这里简单说明一下依赖库的作用fastapiWeb 框架用于提供 HTTP 接口。uvicornASGI 服务器负责运行 FastAPI 应用。akshare财经数据接口库提供 A 股、港股、美股等行情数据。pandas处理表格数据方便把数据转成 JSON。openaiOpenAI Python SDK可以直接兼容 Ollama 的 API。python-dotenv读取 .env 配置文件方便管理模型地址等参数。3.3 安装并启动 Ollama打开 Ollama 官网下载对应操作系统的安装包。安装完成后打开命令行执行ollama --version如果正常输出版本号说明安装成功。然后拉取模型。以下用 Qwen2.5 7B 的量化版本举例ollama pull qwen2.5:7b下载完成后启动模型服务。Ollama 默认监听 11434 端口无需手动启动服务执行模型命令后会自动在后台运行。也可以显式执行ollama serve启动后可以用下面的命令测试模型是否可用curl http://localhost:11434/v1/chat/completions \ -H Content-Type: application/json \ -d { model: qwen2.5:7b, messages: [ {role: user, content: 用一句话介绍你自己} ] }如果能返回 JSON 格式的回复说明 Ollama 已经可以作为 API 服务使用了。4. 获取股票数据这一节我们实现系统的数据层。AKShare 提供了非常丰富的接口我们可以用它获取基础行情数据。4.1 获取实时行情以 A 股为例获取单只股票实时行情可以使用如下代码。新建文件data_fetcher.py# 文件路径stock-ai-analysis/data_fetcher.py import akshare as ak import pandas as pd def get_spot_data(symbol: str): 获取 A 股单只股票实时行情 :param symbol: 股票代码例如 600519 :return: dict 行情数据 # 获取 A 股实时行情数据。该接口返回全市场快照可以按代码过滤。 df ak.stock_zh_a_spot_em() row df[df[代码] symbol] if row.empty: raise ValueError(f未找到股票代码 {symbol}请检查代码是否正确) row row.iloc[0] return { 代码: row[代码], 名称: row[名称], 最新价: float(row[最新价]), 涨跌幅: float(row[涨跌幅]), 涨跌额: float(row[涨跌额]), 成交量: float(row[成交量]), 成交额: float(row[成交额]), 换手率: float(row[换手率]), 市盈率: float(row[市盈率-动态]) if not pd.isna(row[市盈率-动态]) else None, 市净率: float(row[市净率]) if not pd.isna(row[市净率]) else None, } if __name__ __main__: data get_spot_data(600519) print(data)执行测试python data_fetcher.py如果网络正常会输出贵州茅台的相关行情数据。这里有一个需要注意的点stock_zh_a_spot_em()返回的是全市场快照默认有几万条数据。如果你只查一只股票可能会有约 2 秒的等待这是正常的。4.2 获取历史日线数据历史数据用于计算简单的趋势指标比如最近 5 日和 20 日均线。# 继续在 data_fetcher.py 中添加以下函数 def get_history_data(symbol: str, days: int 30): 获取 A 股单只股票历史日线数据 :param symbol: 股票代码 :param days: 获取最近多少天 :return: DataFrame # 这里使用后复权方式获取历史行情 df ak.stock_zh_a_hist( symbolsymbol, perioddaily, start_date20200101, end_date20500101, adjustqfq, ) # 只需要最近 days 条数据 df df.tail(days).reset_index(dropTrue) return df注意AKShare 的接口参数可能会随版本更新而调整。如果你在运行时报参数错误先用pip show akshare查看版本再查阅对应版本的官方文档。4.3 整理成结构化字典为了让大模型更容易理解数据我们需要把 DataFrame 转换为 JSON 友好的结构。继续扩展def get_analysis_data(symbol: str) - dict: 获取用于分析的汇总数据 spot get_spot_data(symbol) history get_history_data(symbol, 30) # 取最近收盘价序列 close_list history[收盘].tolist() # 简单计算均线 ma5 round(sum(close_list[-5:]) / 5, 2) if len(close_list) 5 else None ma10 round(sum(close_list[-10:]) / 10, 2) if len(close_list) 10 else None ma20 round(sum(close_list[-20:]) / 20, 2) if len(close_list) 20 else None return { 实时行情: spot, 最近5日均价: ma5, 最近10日均价: ma10, 最近20日均价: ma20, 近5日收盘价: close_list[-5:], 近20日收盘价: close_list[-20:], }5. 接入大模型并生成分析报告数据准备好之后接下来是关键一步把数据组装成提示词发送给本地大模型。5.1 配置模型连接信息新建.env文件用来存放模型地址和模型名称# OpenAI 兼容 API 地址 LLM_BASE_URLhttp://localhost:11434/v1 # 模型名称 LLM_MODELqwen2.5:7b # API Key本地服务可随意填写 LLM_API_KEYollama之所以使用环境变量是因为后续如果切换到云端大模型只需要改.env不需要改代码。5.2 设计提示词模板提示词是决定输出质量的关键。为了让大模型输出稳定提示词需要包含 3 部分信息角色设定。数据内容。输出格式要求。下面是一个完整的提示词模板新建prompt_builder.py# 文件路径stock-ai-analysis/prompt_builder.py import json def build_stock_prompt(stock_data: dict, stock_name: str) - str: 构造面向股票分析场景的提示词 data_json json.dumps(stock_data, ensure_asciiFalse, indent2) prompt f 你是一位资深股票分析师擅长从技术面与基本面角度分析 A 股上市公司。 请根据以下提供的结构化行情数据输出一份简洁的投资研究简报。 注意 1. 只基于给定数据分析不能编造数据。 2. 分析要客观既要指出积极因素也要指出潜在风险。 3. 使用中文输出控制在 300 字以内。 4. 严格按照以下 Markdown 结构输出 ## 股票概况 ## 技术面分析 ## 基本面观察 ## 风险提示 ## 综合观点 股票名称{stock_name} 结构化数据如下 {data_json} return prompt这里有几个设计细节值得说明使用json.dumps序列化数据保证数据结构清晰。在提示词中明确“不能编造数据”降低大模型幻觉概率。指定输出结构有利于前端解析渲染。限制字数避免响应时间过长。5.3 调用大模型接口新建llm_service.py实现调用 OpenAI 兼容接口的逻辑# 文件路径stock-ai-analysis/llm_service.py import os from openai import OpenAI from dotenv import load_dotenv from prompt_builder import build_stock_prompt load_dotenv() BASE_URL os.getenv(LLM_BASE_URL, http://localhost:11434/v1) MODEL os.getenv(LLM_MODEL, qwen2.5:7b) API_KEY os.getenv(LLM_API_KEY, ollama) client OpenAI(base_urlBASE_URL, api_keyAPI_KEY) def analyze_stock(stock_data: dict, stock_name: str) - str: 调用大模型生成股票分析报告 prompt build_stock_prompt(stock_data, stock_name) try: completion client.chat.completions.create( modelMODEL, messages[ {role: system, content: 你是一名严谨的金融数据分析助手。}, {role: user, content: prompt}, ], temperature0.4, max_tokens800, ) return completion.choices[0].message.content except Exception as e: return f调用大模型失败{e}这里设置temperature0.4是为了减少随机性让分析结果更稳定。金融场景不需要太多“创造性”。5.4 测试分析链路在项目根目录新建临时测试脚本python -c from data_fetcher import get_analysis_data from llm_service import analyze_stock data get_analysis_data(600519) report analyze_stock(data, 贵州茅台) print(report) 预期输出结果是一段 Markdown 格式的分析报告。如果输出的是“调用大模型失败”请检查 Ollama 服务是否启动以及.env配置是否正确。6. 搭建 FastAPI 后端服务数据层和模型层都准备好之后我们使用 FastAPI 把它们串成 HTTP 接口。6.1 创建主应用新建main.py# 文件路径stock-ai-analysis/main.py from fastapi import FastAPI, Query, HTTPException from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import FileResponse, JSONResponse from data_fetcher import get_analysis_data from llm_service import analyze_stock app FastAPI(title股票 AI 分析系统) # 允许前端跨域访问 app.add_middleware( CORSMiddleware, allow_origins[*], allow_methods[*], allow_headers[*], ) app.get(/) def index(): return FileResponse(index.html) app.get(/api/stock/data) def get_stock_data(symbol: str Query(..., description股票代码例如 600519)): 获取原始股票数据 try: data get_analysis_data(symbol) return JSONResponse(contentdata) except ValueError as e: raise HTTPException(status_code404, detailstr(e)) except Exception as e: raise HTTPException(status_code500, detailf数据获取失败{e}) app.get(/api/stock/analyze) def get_stock_analysis(symbol: str Query(..., description股票代码)): 获取 AI 分析报告 try: data get_analysis_data(symbol) stock_name data[实时行情][名称] report analyze_stock(data, stock_name) return JSONResponse(content{report: report}) except ValueError as e: raise HTTPException(status_code404, detailstr(e)) except Exception as e: raise HTTPException(status_code500, detailf分析失败{e})接口设计说明/api/stock/data返回结构化数据便于调试。/api/stock/analyze返回 AI 分析报告前端直接用 innerHTML 渲染 Markdown。异常统一处理避免前端拿到不明确错误。6.2 创建简易前端页面为了演示效果新建index.html放在项目根目录!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title股票 AI 分析系统/title style body { font-family: Microsoft YaHei, sans-serif; max-width: 900px; margin: 40px auto; padding: 0 20px; background: #f7f9fc; color: #2c3e50; } h1 { text-align: center; } .search-box { display: flex; gap: 12px; margin: 20px 0; } input { flex: 1; padding: 10px; font-size: 16px; border-radius: 6px; border: 1px solid #ccc; } button { padding: 10px 20px; font-size: 16px; background: #3498db; color: #fff; border: none; border-radius: 6px; cursor: pointer; } button:disabled { background: #95a5a6; } #result { background: #fff; border-radius: 8px; padding: 20px; box-shadow: 0 2px 8px rgba(0,0,0,0.08); margin-top: 20px; line-height: 1.8; } /style /head body h1 专属股票 AI 分析系统/h1 p styletext-align:center;color:#7f8c8d;输入 A 股代码生成多维度分析简报/p div classsearch-box input typetext idsymbol placeholder例如600519 贵州茅台 value600519 button idanalyzeBtn onclickanalyze()AI 分析/button /div div idresult请在左侧输入股票代码点击“AI 分析”按钮。/div script async function analyze() { const symbol document.getElementById(symbol).value.trim(); const btn document.getElementById(analyzeBtn); const result document.getElementById(result); if (!symbol) { result.innerHTML p stylecolor:#e74c3c请输入股票代码/p; return; } btn.disabled true; btn.textContent 分析中...; result.innerHTML p正在获取行情数据并调用大模型请稍候.../p; try { const response await fetch(/api/stock/analyze?symbol${encodeURIComponent(symbol)}); const data await response.json(); if (!response.ok) { result.innerHTML p stylecolor:#e74c3c错误${data.detail || 未知错误}/p; return; } // 简单处理 Markdown把 # 转成对应标题标签 const html data.report .replace(/^### (.*)$/gm, h3$1/h3) .replace(/^## (.*)$/gm, h2$1/h2) .replace(/\*\*(.*)\*\*/g, strong$1/strong) .replace(/\n/g, br); result.innerHTML html; } catch (err) { result.innerHTML p stylecolor:#e74c3c请求失败${err.message}/p; } finally { btn.disabled false; btn.textContent AI 分析; } } /script /body /html这里的前端渲染做了最简化的 Markdown 转换适合演示。生产环境建议引入marked.js或markdown-it。6.3 启动服务并测试在项目根目录执行uvicorn main:app --host 0.0.0.0 --port 8000打开浏览器访问http://localhost:8000输入股票代码后点击“AI 分析”。如果一切正常你应该能看到类似这样的结构化报告## 股票概况 贵州茅台今日最新价 1680.00 元涨跌幅 1.25%市盈率 31.2。 ## 技术面分析 近5日均价 1655.20近20日均价 1600.80短期均线高于长期均线多头排列特征明显。 ## 基本面观察 市盈率处于合理区间市净率 8.6说明市场对品牌溢价给予了较高估值。 ## 风险提示 1. 短期涨幅较大存在回调压力。 2. 高估值水平对业绩增长要求较高。 ## 综合观点 整体趋势向好但短期不宜追高建议关注回调后的买入机会。注意不同模型的输出内容会有差异这是正常的。我们更关注的是输出的结构和逻辑是否稳定。7. 常见问题与排查思路在部署和运行过程中最容易踩坑的几个点如下。问题现象常见原因解决思路Ollama API 请求超时模型体积大首次推理需要加载时间等待片刻重试或使用显存更大的机器模型返回乱码模型不支持中文或提示词编码异常换用 Qwen 等中文模型检查终端编码AKShare 拉取数据报错接口更新或网络无法访问数据源升级 akshare 库检查网络代理设置端口被占用8000 或 11434 端口已被其他程序占用使用lsof -i:8000或netstat -ano查看占用进程CORS 跨域报错前端页面与后端端口不同如分开部署按需配置 allow_originsFastAPI 返回 500数据结构异常或字段不存在打印异常详情检查 pandas 字段名7.1 Ollama 模型启动慢如果你在 CPU 环境运行 7B 模型首轮请求可能需要 10 到 30 秒。这属于正常现象不要误以为程序卡死。建议使用ollama ps查看模型加载状态。另外Ollama 默认会分配可用内存的一部分作为模型上下文。如果你的内存只有 8GB可以考虑拉取更小的模型ollama pull qwen2.5:3b7.2 AKShare 数据源失效AKShare 依赖网络接口部分数据源会有访问频率限制。如果你在短时间内大量请求可能触发反爬机制。解决方案是增加缓存同一只股票在 5 分钟内不重复拉取。下面是一个简单的装饰器缓存实现import time from functools import wraps _cache {} def ttl_cache(seconds: int 300): def decorator(func): wraps(func) def wrapper(*args, **kwargs): key (args, tuple(kwargs.items())) now time.time() if key in _cache and now - _cache[key][0] seconds: return _cache[key][1] result func(*args, **kwargs) _cache[key] (now, result) return result return wrapper return decorator # 使用方式 ttl_cache(seconds300) def get_spot_data(symbol: str): # 原逻辑 pass7.3 大模型输出不稳定同一个提示词大模型多次输出可能不完全一致。对于股票分析场景建议在提示词中加入“严格按照给定数据结构输出”的约束同时在后端对输出做一次后处理。例如如果输出缺少“风险提示”部分可以提示用户重新生成或者拼接固定兜底文案。8. 最佳实践与工程建议文章到这里主体功能已经全部跑通。但如果只是能跑通还不足以称为“工程化”。下面写几条我在实际项目中比较注重的实践。8.1 提示词版本化很多人把提示词直接写在代码里调试起来非常痛苦。更好的做法是把提示词模板放到单独文件例如prompts/stock_analysis.md。修改时不需要动代码也可以使用类似 Git 的方式对提示词做版本管理。提示词模板中建议使用占位符例如{stock_data}这样既能复用模板也方便批量测试。8.2 增加模型输出校验大模型返回的内容不一定符合预期格式。建议在接口层增加简单校验def validate_report(report: str) - bool: required_sections [股票概况, 技术面分析, 风险提示, 综合观点] for section in required_sections: if section not in report: return False return True校验不通过时可以自动重试一次或者返回提示让用户稍后再试。这个环节能显著提升用户体验。8.3 数据缓存与限流股票数据在盘中会频繁变动但 1 分钟内的变化对分析结果影响不大。建议在系统层面增加数据缓存避免重复请求 AKShare。接口限流防止恶意刷接口导致数据源被封。日志记录记录每次请求的股票代码、耗时、模型输出状态。FastAPI 可以使用慢速限流中间件也可以简单使用字典加时间戳实现。8.4 安全与合规意识股票数据涉及金融场景需要特别注意以下原则只在合法授权的范围内使用数据注意数据源的使用条款。分析结果必须附加免责声明避免被误用为投资建议。本文的本地部署模式虽然隐私较好但如果对外开放服务仍需做好接口鉴权。生产环境不建议直连数据库或数据源应增加中间层隔离。8.5 用 AI 编程工具加速开发本文代码虽然可以手写完成但实际开发中使用 Cursor、Codex 等 AI 编程工具会更快。你可以尝试把“编写 AKShare 数据获取函数”“设计 FastAPI 接口”“生成前端页面”作为任务描述让 AI 辅助生成初版代码再手动检查和调整。FDE 的核心不是“完全交给 AI”而是“人机协作”。AI 负责模板化、重复性代码人负责架构设计、数据合规和异常处理。这也是我在推荐这条技术路线时最想传递的观念。9. 后续扩展方向目前系统已经实现了“数据获取 大模型分析 Web 展示”的闭环。如果再往前走可以扩展以下能力。9.1 多股票对比分析将单只股票分析扩展为多只股票对比例如让大模型同时分析“贵州茅台、五粮液、泸州老窖”三只白酒股输出横向对比结论。实现方式是在提示词中传入多份结构化数据然后要求模型按对比维度输出。9.2 接入新闻与公告AKShare 同样提供新闻和公告接口。你可以把最近 3 天的公告标题和摘要加入提示词让大模型结合消息面进行分析。不过要控制输入长度避免超出模型上下文窗口。9.3 定时任务与日报推送使用 APScheduler 或系统 cron 定时执行分析并把报告发送到钉钉、企业微信或邮件。这样每天开盘前就能收到一份 AI 生成的行情追踪日报。需要注意的是定时任务必须处理异常重试避免单次失败导致整天没有报告。9.4 基于向量库的投研知识库如果希望大模型能回答更复杂的金融问题可以把研报、财报、历史文章存入向量数据库使用 RAG 模式构建知识库问答系统。这时“股票分析系统”会升级为“投研助手”。这也是大模型在金融领域落地更深入的方向。10. 最后说几句从搭建环境、部署大模型到抓取股票数据、完成 AI 分析接口我们走完了一条完整的“大模型应用落地”链路。这个过程看起来简单但其中包含了不少工程细节数据格式如何设计、提示词怎么写更稳、接口异常如何处理、数据合规如何保证。这些能力恰恰是当前 FDE 和 AI 应用工程师最需要积累的。如果你跟着本文完成了部署下一步建议你自己改一两个地方换一只股票测试换一个模型对比输出效果或者修改提示词模板增加分析维度。动手改一遍比只看文章有效得多。如果这篇教程对你有帮助可以收藏备用。也欢迎在评论区聊聊你遇到的其他报错或者分享你扩展出来的新功能。
返回列表