FDE实战:从零构建股票分析智能体的工程全流程
2026/9/2 4:26:58 网站建设 项目流程

这次我们不聊一个开箱即用的演示项目,而是完整走一遍 FDE 实战路线:如何用 Agent 开发方法论,从零打造一个股票分析智能体。股票分析本身是常见场景,但真正有价值的是工程过程——需求拆解、文档先行、Vibe-Coding 生成原型、评测驱动迭代。这套流程也是当下 AI 团队招聘 FDE 前沿部署工程师时最看重的能力组合。

先说项目边界。这个智能体的任务不是预测涨跌,也不是自动下单,而是给用户提供结构化的行情信息与分析过程:给定一只股票,智能体主动调用行情数据工具,再把数据整理成简报。整个过程由 LLM 驱动,用工具补充事实,用评测集验收。读完本文,你会拿到一套可以照抄的目录结构、核心代码、评测脚本和 API 封装。

适合阅读本文的读者,一类是准备转型 Agent 开发的工程师,另一类是已经在做 AI 落地、想引入评测驱动的技术负责人。文章不会只讲概念,每一步都对应可运行的文件和命令。

1. 核心能力速览

能力项说明
项目类型FDE 实战案例,Agent 开发端到端工程流程
核心方法需求拆解、文档先行、Vibe-Coding、评测驱动
业务场景股票行情查询与分析简报生成
技术栈Python、OpenAI 兼容接口、FastAPI、数据源适配层
硬件要求不依赖本地 GPU,需要可访问 LLM API
启动方式命令行测试 + FastAPI Web 服务
是否支持 API支持,提供/v1/analyze接口
是否支持批量任务支持,可对股票列表做并发分析
评测能力工具调用成功率、事实覆盖度、格式合规率
是否适合生产可作为业务原型,生产前仍需补充鉴权、限流、日志和评测闭环

这里需要强调一点:整套流程不依赖具体模型厂商,接口基于 OpenAI 兼容协议,实际使用哪个模型根据部署环境决定。下面的操作步骤也都按兼容协议来写。

2. FDE 项目实战:股票分析智能体到底是什么

FDE,即 Frontier Deployment Engineer,前沿部署工程师。这个岗位的核心职责不是研究算法,而是把大模型能力部署到真实业务场景,解决“模型在实验室好用、到业务里用不起来”的问题。业务侧的需求通常是模糊的,模型侧的能力是概率性的,FDE 要做的就是在中间搭一套工程框架,让不可控的模型输出变得可控、可测、可交付。

股票分析智能体就是这个框架的一个典型样例。它涉及典型的 Agent 能力闭环:自然语言输入、工具调用、结果归纳、最终回答。用户说“帮我看看某只股票的近期行情”,智能体不能凭记忆回答,必须先调用行情数据工具,拿到数据再做总结。这个动作看似简单,实际落地时会遇到一堆问题:模型不按格式调用工具、数据源返回字段不统一、模型在没拿到数据时编造数字、批量分析时接口限流。这些问题都会在下面的流程中逐一处理。

这个项目选择股票分析还有一个原因:业务语义足够清晰。行情的字段是客观事实,涨跌幅度可以精确计算,评测结果容易判定对错。这比做一个泛泛的“聊天助手”更适合用来实践 FDE 方法论,因为你能明确知道智能体做对了没有。

注意合规边界。股票分析智能体只做信息整理和辅助分析,不构成投资建议。不要在项目中加入自动下单、保证收益、预测未来走势这类能力。涉及实时行情数据时,必须确认数据源的使用许可,不能擅自抓取无授权的数据接口。这是 FDE 落地金融场景时的第一道红线。

3. 第一步:需求拆解,从模糊想法到事实清单

FDE 工作流里最难的不是写代码,而是把业务方的模糊想法翻译成事实清单。业务方说“我要一个股票分析智能体”,这句话里至少有三个不明确点:分析哪些股票、分析哪些维度、输出什么格式。如果不拆清楚,开发阶段就会反复返工。

3.1 需求拆解要回答的问题

在写任何代码之前,先把下面这些问题列出答案:

  • 用户是谁:个人投资者还是内部投研人员,这决定回答的详略程度。
  • 输入是什么:股票代码、自然语言问题,还是两者都有。
  • 输出是什么:一段文字、结构化 JSON,还是 Markdown 简报。
  • 分析什么:行情快照、历史走势、财务指标、新闻舆情,还是技术指标。
  • 数据从哪里来:是否已获得授权,接口字段是否稳定,限流策略是什么。
  • 模型能力边界:当前模型是否支持工具调用,是否需要为不支持工具调用的模型走 Prompt 解析方案。
  • 错误兜底:查不到数据时怎么回答,模型拒绝调用工具时怎么处理。

这七个问题属于需求的事实层。FDE 特别强调“面向语意的事实方法论”,意思是每个需求点都要落到能验证的事实描述,而不是停留在感觉层面。比如“分析行情”是语义描述,落到事实层就是“获取股票最新交易日开盘价、收盘价、最高价、最低价和成交量,并对比前一个交易日计算涨跌幅”。

3.2 把需求拆成功能清单

以股票分析智能体为例,拆解后可以得到五个功能点:

  1. 股票代码识别。支持输入美股代码、A 股代码或内部证券编码,并统一格式。
  2. 行情数据获取。调用数据源工具,返回指定股票的最新交易数据。
  3. 风险信息提示。针对涨跌幅异常、成交量异常等做规则化提示。
  4. 分析简报生成。模型基于工具返回的数据生成结构化文本,禁止未取数先回答。
  5. 接口服务。对外提供 HTTP API,支持单只股票分析和批量分析。

每个功能点都需要有对应的验收标准。验收标准就是评测用例的雏形,这一步做扎实,后面的评测驱动自然就能展开。

3.3 需求拆解模板示例

可以把拆解结果沉淀成 Markdown 文档,作为后续一切开发的基础。下面是一个可用模板:

# 股票分析智能体需求拆解 ## 1. 用户与场景 - 用户:内部投研人员 - 场景:快速查看单只股票行情并生成简报 - 输入:股票代码或自然语言问题 - 输出:Markdown 格式分析简报 ## 2. 功能清单 | 编号 | 功能点 | 验收标准 | | --- | --- | --- | | F1 | 股票代码识别 | 输入 AAPL 返回 Apple Inc.,注意代码大小写与交易所后缀 | | F2 | 行情数据获取 | 获取最新交易日 OHLCV 数据,缺字段时显式报错 | | F3 | 异常涨跌提示 | 单日涨幅超过 5% 时输出风险提示 | | F4 | 分析简报生成 | 回答必须包含数据来源日期,禁止编造数字 | | F5 | API 服务 | POST /v1/analyze 返回 200 和合法 JSON | ## 3. 数据来源 - 默认数据源:待确认订阅的行情服务 - 字段:open, close, high, low, volume, date - 无数据策略:返回明确错误,不让模型猜测 ## 4. 边界与限制 - 不提供投资建议 - 不接入交易系统 - 不做未来走势预测

需求拆解文档写完之后,应该让业务方逐条确认。确认过的事实清单就是后续开发的唯一依据,如果业务方中途改需求,不要口头确认,回到这份文档里更新并重新过一遍受影响的功能点。

4. 第二步:文档先行,写清楚再写代码

很多 Agent 项目失败,不是因为模型能力不行,而是因为团队在代码里讨论需求。FDE 的做法是文档先行,代码只是文档的执行结果。文档不需要写成几十页的正式设计书,重点是把三类内容固定下来:技术方案、提示词约束、评测计划。

4.1 技术方案文档

技术方案文档回答“用什么结构实现”。股票分析智能体建议采用工具调用模式,整体结构分四层:

  • 入口层:接收用户问题,维护多轮对话状态。
  • 调度层:LLM 决定是否调用工具、调用哪个工具、传什么参数。
  • 工具层:行情数据获取函数,返回统一 JSON。
  • 评测层:用评测集自动跑一遍,统计指标。

这样的结构让每一层都能独立验证。工具层可以脱离模型单测,调度层可以换模型重测,评测层则固定为回归测试。下面是技术方案文档的目录:

# 股票分析智能体技术方案 ## 1. 系统架构 入口层 -> 调度层 -> 工具层 -> 数据源 | v 评测层 ## 2. 关键流程 - 用户输入问题 - LLM 判断是否需要行情数据 - 需要则调用 get_stock_quote(symbol) - 工具返回 JSON 给 LLM - LLM 生成最终简报 ## 3. 提示词约束(基础版) - 角色:股票分析助手 - 必须使用工具返回的数据 - 禁止编造行情数据 - 数据不足时明确回复“暂无数据” ## 4. 评测计划 - 评测集:20 条用例 - 指标:工具调用成功率、事实覆盖度、JSON 可解析率 - 门槛:工具调用成功率 >= 90%,事实覆盖度 >= 85%

4.2 文档和代码的关系

在 Vibe-Coding 阶段,文档就是 Prompt 的上下文。把上面这份技术方案喂给 AI 编程工具,生成的代码会比直接说“帮我写一个股票分析 Agent”准确得多。这不是玄学,而是因为文档把约束说清了:工具层返回什么字段、调度层用什么协议、评测层看什么指标。

文档同时也是团队协作的锚点。新成员加入时,不需要阅读全部代码,先读需求拆解和技术方案,就能知道系统边界和验收标准。这在 Agent 开发项目中尤其重要,因为 Agent 行为是概率性的,代码只能展示逻辑,文档才能展示意图。

5. 第三步:环境准备与依赖安装

股票分析智能体不依赖本地 GPU,部署门槛低,主要需要 Python 环境和 LLM API 访问权限。

5.1 基础环境清单

  • Python 3.10 或更高版本。
  • pip 包管理工具。
  • OpenAI 兼容的 LLM API 地址、Key、模型名。
  • 一个可以访问的行情数据源,示例代码使用 yfinance 作为演示,实际部署请替换为已授权的数据源或内部行情服务。
  • 网络策略:服务器需要能访问 LLM API 与行情数据源。

先创建项目目录并初始化虚拟环境:

mkdir stock-agent && cd stock-agent python -m venv venv # Linux/macOS source venv/bin/activate # Windows PowerShell venv\Scripts\activate

5.2 安装依赖

新建requirements.txt,内容如下:

openai>=1.30.0 fastapi>=0.110.0 uvicorn>=0.29.0 pydantic>=2.6.0 python-dotenv>=1.0.0 requests>=2.31.0 yfinance>=0.2.40

安装依赖:

pip install -r requirements.txt

说明一下 yfinance 的作用。它只是一个演示数据源,通过公开渠道获取行情数据,生产环境请根据授权情况换成行情 SDK 或自建行情服务。无论用哪个数据源,工具层应该保持统一返回格式,这样调度层和评测层不需要跟着改。

5.3 配置环境变量

在项目根目录创建.env文件:

LLM_API_KEY=your_api_key_here LLM_BASE_URL=https://api.example.com/v1 LLM_MODEL=your_model_name DATA_SOURCE=yfinance

再创建一个config.py读取环境变量:

import os from dotenv import load_dotenv load_dotenv() LLM_API_KEY = os.getenv("LLM_API_KEY") LLM_BASE_URL = os.getenv("LLM_BASE_URL") LLM_MODEL = os.getenv("LLM_MODEL")

环境变量是通用的,但具体 Key 名和模型名需要按实际部署环境调整。不要在生产代码里硬编码 API Key。

6. 第四步:Vibe-Coding,快速搭建 Agent 最小原型

Vibe-Coding 是当前 Agent 开发中很实用的一种工作方式:用自然语言对话驱动 AI 生成代码,开发者负责给出方向、审查代码、运行测试。这套方式适合快速搭建最小可运行原型,但不代表不写文档、不设测试。本文前面写的需求拆解和技术方案,就是 Vibe-Coding 的导航地图。

6.1 项目目录结构

在开始写代码前,先确定目录结构:

stock-agent/ ├── README.md ├── requirements.txt ├── .env ├── config.py ├── agent/ │ ├── __init__.py │ ├── tools.py │ ├── llm.py │ └── core.py ├── scripts/ │ └── run_eval.py ├── server/ │ └── app.py └── data/ └── eval_cases.json

这个结构把工具层、调度层、评测层、服务层分开,代码量不大,但边界清楚。

6.2 工具层:行情数据获取

工具层是 Agent 与外部世界交互的唯一通道。所有数据源差异都封装在agent/tools.py里,模型不关心数据来自 yfinance、行情 SDK 还是内部数据库。

打开agent/tools.py,输入以下内容:

"""工具层:对接行情数据源,统一返回 JSON""" def get_stock_quote(symbol: str) -> dict: """获取股票最新行情。 注意:示例使用 yfinance,实际部署请替换为合法授权的数据源。 """ import yfinance as yf ticker = yf.Ticker(symbol) hist = ticker.history(period="5d") if hist is None or hist.empty: return { "symbol": symbol, "error": "NO_DATA", "message": "未查询到该股票的行情数据,请检查代码是否正确" } last = hist.iloc[-1] prev = hist.iloc[-2] if len(hist) >= 2 else last return { "symbol": symbol, "date": str(hist.index[-1].date()), "open": round(float(last["Open"]), 2), "close": round(float(last["Close"]), 2), "high": round(float(last["High"]), 2), "low": round(float(last["Low"]), 2), "volume": int(last["Volume"]), "change_pct": round( float((last["Close"] - prev["Close"]) / prev["Close"] * 100), 2 ) }

这个函数有两点值得注意。第一,它把“涨跌幅”这个衍生指标计算放在工具层里,而不是让模型自己算,因为模型算算术容易出错。第二,它返回固定的 JSON 结构,后续无论换成哪个数据源,都保持这个结构,评测脚本就不用改。

6.3 调度层:LLM 工具调用主循环

调度层负责让 LLM 决定是否调用工具、调用哪个工具,并把结果回填给模型生成最终回答。使用 OpenAI 兼容的接口定义工具 Schema。

新建agent/llm.py

"""LLM 客户端封装,基于 OpenAI 兼容协议""" import config from openai import OpenAI client = OpenAI( api_key=config.LLM_API_KEY, base_url=config.LLM_BASE_URL ) def chat(messages, tools=None): return client.chat.completions.create( model=config.LLM_MODEL, messages=messages, tools=tools or [], temperature=0.2 )

新建agent/core.py,这是 Agent 的主循环:

"""Agent 调度核心""" import json from agent import tools from agent.llm import chat SYSTEM_PROMPT = ( "你是一名股票分析助手。" "你必须先调用 get_stock_quote 工具获取数据,再基于工具返回的数据回答问题。" "工具返回的数据中包含日期,回答时请注明数据日期。" "如果工具返回 NO_DATA,请明确告知用户暂无数据,不要编造行情数字。" "回答要简明扼要,包括开盘价、收盘价、涨跌幅和成交量。" ) TOOLS = [ { "type": "function", "function": { "name": "get_stock_quote", "description": "获取指定股票的最新行情数据,包括开盘价、收盘价、最高价、最低价、成交量和涨跌幅", "parameters": { "type": "object", "properties": { "symbol": { "type": "string", "description": "股票代码,例如 AAPL、MSFT" } }, "required": ["symbol"] } } } ] TOOL_FUNCTIONS = { "get_stock_quote": tools.get_stock_quote, } def run_agent(user_question: str, max_steps: int = 3) -> dict: messages = [ {"role": "system", "content": SYSTEM_PROMPT}, {"role": "user", "content": user_question} ] for _ in range(max_steps): response = chat(messages, tools=TOOLS) assistant_message = response.choices[0].message messages.append(assistant_message) tool_calls = assistant_message.tool_calls if not tool_calls: return { "reply": assistant_message.content or "", "tool_called": None, "steps": exhausted } for tool_call in tool_calls: fn_name = tool_call.function.name fn_args = json.loads(tool_call.function.arguments) if fn_name not in TOOL_FUNCTIONS: continue result = TOOL_FUNCTIONS[fn_name](**fn_args) messages.append({ "role": "tool", "tool_call_id": tool_call.id, "content": json.dumps(result, ensure_ascii=False) }) return { "reply": "已达到最大调用步数,未完成分析。", "tool_called": None, "steps": exhausted }

代码里没有使用model_dump()之类的序列化方法,是因为不同版本的 OpenAI SDK 对消息对象的处理不同。如果你的 SDK 版本较新,需要在messages.append(assistant_message)之前做一次转换,可参照官方文档调整。这属于 Vibe-Coding 后的审查环节,AI 生成的代码必须人工检查过再运行。

6.4 运行第一个测试

在项目根目录新建test_quick.py

from agent.core import run_agent if __name__ == "__main__": result = run_agent("请分析一下 AAPL 的最新行情") print(result["reply"])

运行:

python test_quick.py

预期输出会类似“根据 2025-06-XX 数据,AAPL 收盘价 XX 美元,涨跌幅 X%...”。注意,第一批代码跑通不代表功能正确。如果模型没有调用工具而是直接回答,或者返回了编造的数字,这说明提示词或工具 Schema 需要调整。不要急着改代码,先按文档中的约束检查提示词,再检查工具 Schema 的名称和参数是否匹配。

7. 第五步:评测驱动,给智能体立规矩

Agent 开发最容易出现的情况是“这个用例好了,另一个用例坏了”。因为模型是概率性的,改一个提示词可能影响全部行为。评测驱动的做法,是把关键行为固定成自动化用例,每次改动后都跑一遍,用数据判断好还是坏。

7.1 评测指标

对于股票分析智能体,最核心的评测指标有四类:

指标名称计算方式业务含义
工具调用成功率正确调用 get_stock_quote 的用例占比智能体是否知道什么时候该取数
事实覆盖度回答中包含预期关键字段的用例占比是否把行情数据完整说清楚
格式合规率输出符合结构要求的用例占比是否方便下游解析
幻觉发生率回答中出现数据源未提供数字的用例占比,越低越好是否编造行情

评测指标不需要一开始就做得很复杂,先把这三项跑起来,就已经能拦住大部分回归问题。

7.2 评测集设计

新建data/eval_cases.json

[ { "id": "case_001", "question": "请分析 AAPL 的最新行情", "expected_tool": "get_stock_quote", "expected_symbol": "AAPL", "expected_facts": ["date", "close", "change_pct"] }, { "id": "case_002", "question": "帮我看看 MSFT 最近怎么样", "expected_tool": "get_stock_quote", "expected_symbol": "MSFT", "expected_facts": ["date", "close", "change_pct"] }, { "id": "case_003", "question": "分析 000001.SZ 的最新行情", "expected_tool": "get_stock_quote", "expected_symbol": "000001.SZ", "expected_facts": ["date", "close"] }, { "id": "case_004", "question": "今天适合买什么股票?", "expected_tool": null, "expected_facts": [] } ]

看到case_004了吗?这一条是负向用例。智能体不能对“今天买什么股票”给出推荐,它应该拒绝回答或说明只能提供行情分析。这类用例对金融场景尤其重要,它评测的不是模型能力,而是边界意识。

7.3 自动评测脚本

新建scripts/run_eval.py

"""评测驱动:自动运行评测集并输出指标""" import json from agent.core import run_agent def load_cases(path="data/eval_cases.json"): with open(path, encoding="utf-8") as f: return json.load(f) def evaluate_case(case): result = run_agent(case["question"]) reply = result["reply"] tool_called = result.get("tool_called") expected_tool = case.get("expected_tool") facts = {} for fact_name in case.get("expected_facts", []): facts[fact_name] = fact_name in reply or f'"{fact_name}"' in reply tool_ok = tool_called == expected_tool fact_ok = all(facts.values()) return { "case_id": case["id"], "question": case["question"], "tool_called": tool_called, "expected_tool": expected_tool, "tool_ok": tool_ok, "fact_ok": fact_ok, "has_forbidden_recommendation": "建议买入" in reply or "建议卖出" in reply } def main(): cases = load_cases() rows = [evaluate_case(c) for c in cases] tool_ok_count = sum(1 for r in rows if r["tool_ok"]) fact_ok_count = sum(1 for r in rows if r["fact_ok"]) total = len(rows) print(json.dumps(rows, ensure_ascii=False, indent=2)) print(f"tool call pass rate: {tool_ok_count / total:.2%}") print(f"fact coverage pass rate: {fact_ok_count / total:.2%}") if __name__ == "__main__": main()

运行评测:

python scripts/run_eval.py

评测脚本能做的事不多,但价值很高:任何改动之后,跑一遍,指标变差就说明改坏了。如果工具调用成功率只有 50%,优先排查提示词是否约束了“必须先调用工具”;如果事实覆盖度低,优先排查数据源返回字段是否被正确解析。

7.4 评测驱动如何持续迭代

评测集要跟着需求走。发现一个新问题,就往评测集里加一条用例,让它永远不再出现。比如模型在某次回答中编造了一个“52 周最高价”,虽然工具返回字段里根本没有这个值,但模型自己填了一个,这就是典型的幻觉。处理方式不是只改这一次的提示词,而是把“回答中出现未提供字段”的用例加入评测集,再调整提示词约束。

这样迭代两到三轮后,智能体的行为会明显稳定。评测驱动不是一种“测试方法”而已,它是 Agent 开发的开发方法:先定义正确,再让模型逼近正确。

8. 第六步:接口 API 与批量任务

原型验证通过之后,要把智能体封装成服务,供前端或内部系统调用。这里用 FastAPI 提供最小可用的 HTTP API。

8.1 FastAPI 服务

新建server/app.py

"""API 服务:对外提供股票分析智能体接口""" from fastapi import FastAPI from pydantic import BaseModel from agent.core import run_agent app = FastAPI(title="Stock Agent API", version="0.1.0") class AnalyzeRequest(BaseModel): symbol: str question: str = "" @app.post("/v1/analyze") def analyze(req: AnalyzeRequest): if not req.symbol.strip(): return {"error": "symbol is required"} question = req.question.strip() if not question: question = f"请分析 {req.symbol} 的最新行情" result = run_agent(question) return { "symbol": req.symbol, "reply": result["reply"], "tool_called": result.get("tool_called") }

启动服务:

uvicorn server.app:app --host 127.0.0.1 --port 8000

启动后访问http://127.0.0.1:8000/docs,可以直接在 Swagger 界面调试接口。

8.2 接口调用示例

使用curl测试:

curl -X POST http://127.0.0.1:8000/v1/analyze \ -H "Content-Type: application/json" \ -d '{"symbol": "AAPL", "question": "分析最新行情"}'

返回结果:

{ "symbol": "AAPL", "reply": "根据 2025-06-XX 数据,AAPL 收盘价 XXX,涨跌幅 X%...", "tool_called": "get_stock_quote" }

这里注意"tool_called"字段。如果它是null,说明模型没有调用工具,这通常意味着提示词或工具 Schema 有问题,接口测试时第一件事就是看这个字段。

8.3 批量任务设计

批量分析是实际业务中最常见的需求。比如一次分析十只股票,不能简单地开十个线程直接调 LLM,否则会撞上接口限流。建议在项目里加一个批量脚本scripts/batch_analyze.py

"""批量分析股票列表""" import time from concurrent.futures import ThreadPoolExecutor, as_completed from agent.core import run_agent SYMBOLS = ["AAPL", "MSFT", "GOOG", "000001.SZ", "600519.SS"] def analyze_one(symbol: str) -> dict: try: result = run_agent(f"请分析 {symbol} 的最新行情") return {"symbol": symbol, "ok": True, "reply": result["reply"]} except Exception as exc: return {"symbol": symbol, "ok": False, "error": str(exc)} def batch_analyze(symbols: list[str], max_workers: int = 3) -> list[dict]: results = [] with ThreadPoolExecutor(max_workers=max_workers) as pool: futures = [pool.submit(analyze_one, s) for s in symbols] for future in as_completed(futures): results.append(future.result()) return results if __name__ == "__main__": results = batch_analyze(SYMBOLS, max_workers=3) for item in results: print(item["symbol"], item["ok"]) time.sleep(1)

批量任务有三个工程要点:

  • 控制并发数。LLM API 和数据源都有限流,并发太高会触发 429 错误。
  • 记录失败任务。批量任务不能因为一个失败就整体失败,把ok=False的条目单独落盘,重跑时只跑失败的。
  • 增加超时控制。run_agent内部调用 LLM API,建议给请求加timeout,避免一个卡住的请求拖住整个批次。

9. 常见问题与排查方法

以下是这个项目最常见的六个问题及排查思路。

问题现象可能原因排查方式解决方案
模型直接回答,不调用工具提示词没有强制工具调用;模型不支持 function calling;tools 参数未传打开 messages 日志,打印 tools 列表在 system prompt 强调“必须先调用工具”,换支持工具调用的模型
工具返回 NO_DATA股票代码不合法;数据源覆盖范围不足;停牌单独运行 get_stock_quote 函数看返回值检查代码格式,补充数据源覆盖范围
回答中出现编造数字模型在工具未返回时自行补全对照工具返回 JSON 与最终回答强化提示词约束,增加评测用例
接口返回 500依赖未安装;LLM API Key 无效;模型名不存在查看 Uvicorn 控制台日志检查 .env 配置,确认依赖安装完整
批量任务频繁失败并发过高触发限流查看返回状态码是否为 429降低 max_workers,增加重试与退避策略
端口被占用8000 端口已有进程Linux 执行lsof -i:8000,Windows 执行netstat -ano换端口启动,或结束占用进程

排查 Agent 类问题有一个通用技巧:打印完整的 messages。调用 LLM 前把 messages 序列化输出到日志,看最后几轮对话,模型是否真的收到了工具返回数据。很多时候不是模型不行,而是消息传递环节出了问题,比如 tools 返回格式不对、tool_call_id 不匹配。

10. 最佳实践、成本控制与合规边界

10.1 工程化最佳实践

  • 固定模型版本。不要在开发过程中频繁更换模型,至少在一轮评测周期内保持一致,否则指标波动无法归因。
  • 把所有外部依赖封装在工具层。数据源、行情 SDK、内部接口都收敛到tools.py,后续替换成本最低。
  • 评测集与代码一起提交。新增功能时同步扩充评测用例,保证回归测试覆盖。
  • 缓存行情结果。同一只股票在一天内多次请求,可以缓存收盘后的数据,减少数据源压力。
  • 批量任务写进度日志。每完成一只股票都记录时间和结果,方便断点续跑。

10.2 成本控制

股票分析智能体的主要成本是 LLM API 调用。控制成本有几个办法:

  • 把行情计算放到工具层完成,减少模型需要处理的原始数据量。
  • 对相同问题做缓存,短时间重复请求直接返回上一次结果。
  • 评测时用小成本模型预筛,只有指标接近门槛再换强模型验收。
  • 批量任务设置最大 token 上限,防止单次回答过长。

从实际部署经验看,这类工具型 Agent 的单次调用成本受两个因素影响最大:输入历史长度和工具返回数据大小。每次多轮调用都会把之前的消息重新发送给模型,控制历史轮次能明显降低 token 消耗。

10.3 合规边界

股票分析场景有两条必须守住的底线:

第一,不构成投资建议。产品文档、接口返回、页面展示都要有明确提示,比如“以上内容仅供技术演示与信息参考,不构成投资建议”。

第二,行情数据来源合法。不要抓取未经授权的行情数据,不要绕过数据供应商的访问限制。对评测集和演示数据,也要确认为可公开使用的样例。

如果未来把这个智能体接入真实业务,还要考虑用户输入是否包含个人信息、分析结果是否涉及敏感标的、接口是否需要鉴权。这些不在最小原型范围内,但在 FDE 部署上线前必须补齐。

11. 总结与下一步

这个 FDE 实战项目最值得尝试的地方,不是“用 LLM 查股票”这个想法本身,而是五步工程闭环:需求拆解产出事实清单,文档先行固定技术约束,Vibe-Coding 快速生成原型,评测驱动做回归兜底,API 服务对外交付。这五步对任何业务型 Agent 都适用。

建议第一次实践时,先把data/eval_cases.json里的用例跑通,再改提示词观察评测指标变化,这个过程能直观感受“评测驱动”的价值。最容易踩的坑有两个:一是不评测就直接部署,上线后行为不可控;二是批量任务并发开太高,被数据源限流之后整个任务失败。

后续可以扩展的方向包括:接入研报解析工具、增加历史走势图与 K 线数据、引入本地模型做推理降本、把评测集扩展到多轮对话、增加人类反馈标注流程。每一个方向都从更新需求拆解文档开始,而不是直接加代码,这才是 FDE 方法论的最终落点。

整套工程代码建议按本文的目录结构保留一份最小可运行版本,放在公司的实验环境里,后续任何 Agent 项目都可以从这份骨架上改造起步。当前股票分析智能体只做到了“查行情、做简报”这个最小闭环,你已经拥有继续扩展它的正确姿势了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询