通过上一篇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

这里推荐一个国内中转https://jiekou.ai,新用户可以获得1美元的调用额度,按照指引修改base_url和调用函数,并接上网址给你的API就可以啦


六、代码做了什么

虽然代码不长,但它已经完成了一次完整的 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,后续文章会讲更多的相关知识

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐