通过上一篇AI 大模型 Agent 开发入门(二):从让AI从“会回答”到“会做事”-CSDN博客,我们学习了大模型和 Agent 的区别,并学习了一些基础概念。

本文将使用大约 60 行 Python,写一个可以获取真实股票历史行情、计算基础技术指标,并自动生成分析报告的 AI Agent。

用户只需要输入:

分析一下苹果公司最近的走势

Agent 就会自动完成下面的工作:

  1. 识别用户想分析的股票;

  2. 调用股票行情工具;

  3. 获取真实历史行情;

  4. 计算均线、收益率和波动率;

  5. 将数据交给大模型;

  6. 生成一份通俗易懂的分析报告。

需要提前说明的是:

本文获取的是真实历史行情,不是代码中手写的模拟数据,但不保证是交易所级实时行情。


一、最终效果

假设用户输入:

分析一下苹果公司最近的走势。

Agent 首先会理解用户的需求,并识别出:

{
  "symbol": "AAPL"
}

随后,Agent 调用股票行情工具:

get_stock_data(symbol="AAPL")

工具可能返回下面这样的结构化数据:

{
  "symbol": "AAPL",
  "date": "最近一个交易日",
  "close": 210.32,
  "change_1d_pct": 1.25,
  "return_20d_pct": 5.68,
  "ma5": 208.74,
  "ma20": 202.16,
  "volatility_20d_pct": 24.53,
  "volume": 53682100
}

大模型收到这些数据后,就可以生成类似下面的分析:

AAPL 最近一个交易日的收盘价为 210.32 美元,
单日上涨 1.25%,最近 20 个交易日累计上涨 5.68%。

当前价格高于 5 日均线和 20 日均线,
说明短期价格表现相对偏强。

不过,最近 20 个交易日的年化波动率为 24.53%,
说明股价仍然存在一定的短期波动风险。


二、股票分析 Agent 的工作流程

这个股票分析 Agent 的完整工作流程可以分成五个步骤。

在这个过程中,大模型主要完成了三项工作:

1. 理解用户问题

用户可以使用自然语言提问,不需要严格按照固定格式输入。

例如:

看看苹果最近走势怎么样。

或者:

AAPL 现在是短期强势还是弱势?

大模型都可以理解用户是在分析苹果公司的股票。

2. 选择并调用工具

大模型会判断当前问题需要股票数据,因此选择调用:

get_stock_data

同时生成工具所需的股票代码参数。

3. 解释工具返回的数据

Python 负责计算数据,但不会主动写分析报告。

大模型会根据收盘价、均线、收益率和波动率,将数字转换成普通读者能够理解的文字。

因此,一个完整的股票分析 Agent 并不是让大模型直接预测股票,而是:

大模型负责理解和解释
Python 负责查询和计算
外部数据源负责提供真实行情


三、项目使用了哪些技术

这个小项目主要包含三个部分。

技术作用
OpenAI Responses API让大模型理解问题并调用工具
Function Calling让模型选择股票数据工具
yfinance获取真实股票历史行情
pandas计算均线、收益率和波动率
JSON在工具与大模型之间传递数据

yfinance 可以通过 Ticker.history() 获取股票的历史市场数据。它是一个开源项目,通过 Yahoo Finance 的公开接口获取数据,但并不是 Yahoo 官方产品,更适合学习、研究和个人项目。


四、安装项目依赖

首先安装需要使用的 Python 库:

pip install -U openai yfinance

建议使用 Python 3.10 或更高版本。

然后配置 OpenAI API Key。

Windows PowerShell:

$env:OPENAI_API_KEY="你的 API Key"

macOS 或 Linux:

export OPENAI_API_KEY="你的 API Key"

OpenAI() 会自动读取环境变量中的 OPENAI_API_KEY


五、约 60 行完整代码

创建一个文件:

stock_agent.py

将下面的代码复制进去:

import json
import yfinance as yf
from openai import OpenAI

client = OpenAI()

def get_stock_data(symbol: str) -> dict:
    df = yf.Ticker(symbol).history(period="6mo", auto_adjust=True)
    if df.empty:
        return {"error": f"没有找到股票:{symbol}"}
    close = df["Close"].dropna()
    returns = close.pct_change().dropna()
    return {
        "symbol": symbol.upper(),
        "date": str(close.index[-1].date()),
        "close": round(float(close.iloc[-1]), 2),
        "change_1d_pct": round(
            float((close.iloc[-1] / close.iloc[-2] - 1) * 100), 2
        ),
        "return_20d_pct": round(
            float((close.iloc[-1] / close.iloc[-21] - 1) * 100), 2
        ),
        "ma5": round(float(close.tail(5).mean()), 2),
        "ma20": round(float(close.tail(20).mean()), 2),
        "volatility_20d_pct": round(
            float(returns.tail(20).std() * 252 ** 0.5 * 100), 2
        ),
        "volume": int(df["Volume"].iloc[-1])
    }

tools = [{
    "type": "function",
    "name": "get_stock_data",
    "description": "获取真实股票行情并计算技术指标",
    "parameters": {
        "type": "object",
        "properties": {
            "symbol": {
                "type": "string",
                "description": "股票代码,如 AAPL、600519.SS、0700.HK"
            }
        },
        "required": ["symbol"],
        "additionalProperties": False
    },
    "strict": True
}]

inputs = [{"role": "user", "content": input("请输入问题:")}]
response = client.responses.create(
    model="gpt-5.6",
    instructions=(
        "你是谨慎的股票分析助手。必须调用工具获取数据;"
        "分析趋势、收益、波动和成交量;不预测涨跌;"
        "结尾声明不构成投资建议。"
    ),
    input=inputs,
    tools=tools
)

inputs += response.output
for item in response.output:
    if item.type != "function_call":
        continue
    result = get_stock_data(**json.loads(item.arguments))
    inputs.append({
        "type": "function_call_output",
        "call_id": item.call_id,
        "output": json.dumps(result, ensure_ascii=False)
    })

final = client.responses.create(
    model="gpt-5.6",
    input=inputs,
    tools=tools
)
print(final.output_text)

你需要提供 OpenAI API 密钥,任选一种方式:

  1. 设置环境变量(推荐):$env:OPENAI_API_KEY = "sk-..." 后再运行
  2. 改代码:第 5 行改为 OpenAI(api_key="sk-...", base_url="...")(如用国内中转/代理服务需指定 base_url

比如我用kimi3API,我做了一下操作

  • 将 client.responses.create(...) 改成了 Kimi 兼容的 client.chat.completions.create(...)
  • 将模型改成 kimi-k3
  • 将 base_url 改成https://api.kimi.com/coding/v1


六、代码做了什么

虽然代码不长,但它已经完成了一次完整的 Agent 工具调用流程。

1. 获取真实股票行情

核心代码是:

df = yf.Ticker(symbol).history(
    period="6mo",
    auto_adjust=True
)

这里的含义是:

  • symbol:股票代码;

  • period="6mo":获取最近六个月数据;

  • auto_adjust=True:对价格进行自动复权处理。

yfinance 的下载接口支持日线、周线、月线以及多种时间范围;本文使用六个月日线,是为了保证能够计算 5 日和 20 日指标。

查询苹果公司可以输入:

AAPL

查询贵州茅台可以尝试:

600519.SS

查询腾讯控股可以尝试:

0700.HK

股票代码最好先在 Yahoo Finance 中搜索确认。


2. 获取最新收盘价

close.iloc[-1]

close 保存了最近六个月的收盘价。

iloc[-1] 表示获取最后一条数据,也就是最近一个交易日的收盘价。

需要注意:

如果当天还没有收盘,日线数据通常对应最近一个已经完成的交易日。


3. 计算单日涨跌幅

计算公式如下:

单日涨跌幅 =
(今日收盘价 ÷ 上一交易日收盘价 - 1)× 100%

对应代码:

(close.iloc[-1] / close.iloc[-2] - 1) * 100

如果计算结果为:

2.35

表示最近一个交易日上涨了约 2.35%。


4. 计算 20 日收益率

(close.iloc[-1] / close.iloc[-21] - 1) * 100

这里比较的是当前收盘价与 20 个交易日前收盘价。

它可以帮助我们判断股票最近一个月左右的整体表现。

例如:

20 日收益率简单理解
大于 0最近 20 个交易日整体上涨
小于 0最近 20 个交易日整体下跌
接近 0最近 20 个交易日整体震荡

这只是一种基础观察,不能单独用于预测未来走势。


5. 计算 5 日和 20 日均线

"ma5": close.tail(5).mean()
"ma20": close.tail(20).mean()

均线可以用于观察一段时间内的平均价格。

一种常见的基础判断方式是:

当前价格 > 5 日均线 > 20 日均线

说明近期价格相对较强。

反过来:

当前价格 < 5 日均线 < 20 日均线

说明近期价格相对较弱。

但均线属于滞后指标,只能描述已经发生的行情,不能保证未来继续上涨或下跌。


6. 计算 20 日年化波动率

代码如下:

returns.tail(20).std() * 252 ** 0.5 * 100

这里首先计算每天的收益率:

returns = close.pct_change().dropna()

然后计算最近 20 个交易日收益率的标准差,并按照一年约 252 个交易日进行年化。

波动率越高,通常说明价格变化越剧烈。

例如,两只股票最近 20 天都上涨了 10%,但它们的过程可能完全不同:

股票 A:每天缓慢上涨
股票 B:先跌 20%,然后快速反弹

两者收益率可能接近,但股票 B 的波动率通常更高。


七、为什么需要调用两次大模型

代码中一共调用了两次模型。

第一次:

response = client.responses.create(...)

它的主要任务是:

理解用户问题,并决定是否调用股票工具

第二次:

final = client.responses.create(...)

它的主要任务是:

读取工具返回的数据,并生成最终分析

所以完整过程并不是:

用户问题 → 大模型直接回答

而是:

用户问题
   ↓
大模型选择工具
   ↓
Python 获取股票数据
   ↓
Python 计算指标
   ↓
大模型解释指标
   ↓
输出分析报告

这也是一个最小版 AI Agent 的核心结构。

八、这个程序有哪些局限

虽然文章标题是“能分析股票的 AI Agent”,但必须明确它的能力边界。

1. 不是交易所级实时行情

yfinance 更适合学习和研究,不适合对时效性、稳定性和授权要求很高的生产交易系统。

2. 只做了基础技术分析

当前程序只计算了:

  • 最新收盘价;
  • 单日涨跌幅;
  • 20日收益率;
  • 5日均线;
  • 20日均线;
  • 20日年化波动率;
  • 最新成交量。

它还没有分析:

  • 市盈率;
  • 营业收入;
  • 净利润;
  • 现金流;
  • 资产负债率;
  • 公司公告;
  • 行业变化;
  • 宏观经济;
  • 新闻和舆情。

3. 大模型的解释不等于投资结论

大模型只是对工具返回的数据进行整理和解释。

它可能出现:

  • 对指标理解不准确;
  • 过度解读短期波动;
  • 忽略数据异常;
  • 使用过于确定的语言。

因此,我们在提示词中明确要求:

不预测涨跌,最后声明不构成投资建议

4. 数据源可能出现限流或连接失败

因为数据来自外部服务,运行时可能受到以下因素影响:

  • 网络连接;
  • 请求频率;
  • 股票代码错误;
  • 节假日或停牌;
  • 数据源接口变化;
  • 请求限流。

正式项目还需要增加重试、超时、缓存和日志。


这只是一个简单的agent demo,后续文章会讲更多的相关知识

更多推荐