URL
服务地址。它决定请求发到哪一个 API;拼错一个字符也不会得到正确结果。
Python在金融中的应用 · 第四部分
这一节沿用上一节生成的 context:它已经包含行情窗口、新闻线索、数据范围和安全边界。现在再学习两条云端路线:一条是 Python 直接请求大模型 API;另一条是在 Coze 中配置一名 Agent,并把设置、测试与归档组织成完整流程。重点是请求可追踪、密钥不泄露、输出有边界。
第一部分 / 路线 A
Python 在本地读取并清洗行情、新闻和 Prompt;模型在云端运行;结果以 JSON 返回给 Notebook。这一部分先让你亲手完成“创建 Key → 保存到 .env → 发送 POST → 保存响应”的完整链路。
.env。outputs,便于核对。上一节解决“把事实整理出来”;这一节解决“如何把事实安全地交给模型、如何拿回结果并检查”。云端模型很擅长把固定格式的数据改写为自然语言,但它不会自动验证新闻真伪,也不能替你完成因果识别。
要调用云端模型,通常需要在服务商控制台创建 API Key。注册、实名认证、付费与可用模型会随平台规则变化;请从本页的官方链接进入控制台,按页面当前流程操作。拿到 Key 后,不要把它粘贴到 Notebook、截图、Word、微信群或 GitHub。
.env;截图和作业中应始终用星号替代。在 Trae 中创建 .env
在项目根目录新建文件,文件名必须是 .env,最前面有一个点。它不是 env.txt,也不是放在 data 文件夹里。
在 .env 写 DEEPSEEK_API_KEY=你的真实密钥。等号左侧是变量名,右侧才是密钥;不要在等号两侧加空格,不要加引号,除非服务商文档明确要求。
在同级新建 .gitignore,其中单独写一行 .env。这样 Git 在默认情况下不会追踪密钥文件。
录制视频、共享屏幕或截图前,关闭 .env 标签页;不要在终端中 print(key)。
# .env 文件的内容:这是文本文件,不是在 Python 单元中运行
DEEPSEEK_API_KEY=sk-请把这里替换为你自己的真实密钥
# .gitignore 文件的内容:至少包含这一行
.env在 Notebook 中安全读取变量
from dotenv import load_dotenv
import os
load_dotenv() # 读取当前项目目录中的 .env
api_key = os.getenv("DEEPSEEK_API_KEY")
if not api_key:
raise RuntimeError(
"没有读取到 DEEPSEEK_API_KEY。请检查 .env 是否在项目根目录,"
"变量名是否拼写正确,然后重启 Notebook 内核。"
)
print("已读取密钥;长度为:", len(api_key))
print("安全检查:只显示前 3 个字符:", api_key[:3] + "***")python-dotenv 读取 .env,并把其中的键值放到当前 Python 进程的环境变量中。None;因此下一行必须检查,不能直接拼接请求头。.env 后,重启内核再运行这段代码,避免读到旧值。这里使用 OpenAI 兼容的 Chat Completions 形式:发送一个 JSON 对象,收到另一个 JSON 对象。官方接口与模型名可能更新,所以运行前应打开官方文档确认 endpoint、模型名、费用与限制。当前示例使用 deepseek-v4-flash,只是为了把请求结构讲清楚,不是对某个模型的推荐。
服务地址。它决定请求发到哪一个 API;拼错一个字符也不会得到正确结果。
请求头。这里包含 Authorization: Bearer … 与 JSON 内容类型。
请求体。里面写模型名、温度和消息列表;必须是 Python 字典,由 json= 自动编码。
import requests
api_url = "https://api.deepseek.com/chat/completions"
headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json",
}
hello_payload = {
"model": "deepseek-v4-flash",
"temperature": 0.2,
"messages": [
{
"role": "system",
"content": "你是课程中的金融信息整理助手。不得提供投资建议。"
},
{
"role": "user",
"content": "用两句话解释:为什么新闻分析必须标注发布时间和来源?"
},
],
}
response = requests.post(
url=api_url,
headers=headers,
json=hello_payload,
timeout=60,
)
print("HTTP 状态码:", response.status_code)
response.raise_for_status()
print("响应顶层字段:", response.json().keys())Bearer 后面有一个空格;缺少它会导致鉴权失败。params=。choices。不要直接写 response.json()["choices"][0]["message"]["content"] 后就假定永远成功。它在正常时很方便,但一旦 API 返回错误对象、额度信息或空列表,学生很难知道问题在哪里。先把响应保存、显示,再逐层检查。
from pathlib import Path
import json
from datetime import datetime
def get_text_from_response(payload):
if "error" in payload:
raise RuntimeError(f"服务端错误:{payload['error']}")
choices = payload.get("choices", [])
if not choices:
raise ValueError("响应中没有 choices;请查看原始 JSON。")
message = choices[0].get("message", {})
content = message.get("content")
if not content:
raise ValueError("choices[0] 中没有 message.content。")
return content.strip()
raw_payload = response.json()
Path("outputs").mkdir(exist_ok=True)
run_id = datetime.now().strftime("%Y%m%d_%H%M%S")
with open(f"outputs/{run_id}_hello_response.json", "w", encoding="utf-8") as f:
json.dump(raw_payload, f, ensure_ascii=False, indent=2)
answer = get_text_from_response(raw_payload)
print(answer)| 现象 | 常见原因 | 第一步怎么排查 |
|---|---|---|
| 401 / 403 | Key 无效、过期、没有权限,或 Header 格式不对。 | 确认变量是否读到;不要把 Key 发给同学;在官方控制台检查状态。 |
| 404 | URL 或 API 路径写错,也可能是旧教程已失效。 | 从官方文档复制 endpoint,不要依赖截图中的旧地址。 |
| 429 | 触发速率、并发或额度限制。 | 停止循环请求,等待后减少频率;查看控制台的限额说明。 |
| 500 / 503 | 服务端暂时不可用。 | 保存状态码与响应文字,稍后重试;不要无限循环。 |
| JSON 解析失败 | 返回的不是 JSON,或网络代理返回了网页。 | 先打印 response.text[:500],不要先猜字段。 |
不要只写“请分析这只股票”。模型会自己补充很多没有给出的背景。课程 Prompt 由四层构成:角色与安全规则、数据事实、输出格式、明确不能完成的事情。这样的结构让老师、同学和未来的你都能看懂模型是依据什么写出结果。
system_prompt = """你是金融事件信息整理助手。
你的工作是解释已经提供的数据,不补充未经核验的事实。
不得给出买入、卖出、仓位、目标价或确定性预测。
如果数据不足,请明确写“无法确认”,不要编造原因。"""
user_prompt = f"""下面是课程练习的结构化上下文。
{context}
请严格使用以下四个标题输出:
一、可直接从数据读出的事实
二、新闻可能涉及的影响渠道
三、目前无法确认的内容
四、数据范围与局限性
每个标题下最多 3 个要点;必须保留数据截止日期;
不得把新闻线索写成已被证明的因果关系。"""
agent_payload = {
"model": "deepseek-v4-flash",
"temperature": 0.2,
"messages": [
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt},
],
}
print(user_prompt[:800])context 嵌入这里,而不是手动复制一个日期。真正发送“金融上下文”并保存报告
try:
response = requests.post(
api_url, headers=headers, json=agent_payload, timeout=60
)
response.raise_for_status()
raw_payload = response.json()
report = get_text_from_response(raw_payload)
Path(f"outputs/{run_id}_report.md").write_text(report, encoding="utf-8")
Path(f"outputs/{run_id}_agent_response.json").write_text(
json.dumps(raw_payload, ensure_ascii=False, indent=2),
encoding="utf-8",
)
print(report)
except requests.Timeout:
print("请求超过 60 秒。请检查网络或稍后重试,不要重复快速点击运行。")
except requests.RequestException as exc:
print("HTTP 请求失败:", exc)
except (ValueError, RuntimeError) as exc:
print("响应内容无法按预期解析:", exc)这一条路线不要求先写 API 代码,而是先在 Coze 的网页或桌面端把一名 Agent 配置、测试和留档。它和前面的 API 路线解决的是同一个任务:把第十一节整理好的 context 交给模型,并得到可检查的四段式说明。区别只在于:这里由平台界面承载 Agent 的身份、模型、技能与测试对话;本地 Python 仍然负责取得数据、清洗数据和生成可追溯的输入。
先看清官方界面与本节边界


不要一登录就急着连接外部数据、发布链接或充值。先用一个不含真实账户、未公开研究数据和个人隐私的信息整理练习,把全流程跑通。平台如果要求完成验证、同意服务协议或选择地区,请按页面当前提示完成;如果某个功能需要付费、管理员批准或额外授权,就先跳过,并在作业记录中写清“当前账户不可用”。
打开上方的 Coze 官方入口。检查浏览器地址栏确实是官方域名后再登录;不要从聊天群、搜索广告或不明短链接中输入手机号、验证码或账号密码。
使用自己的普通账号或课程允许的账号。不要借用老师、同学或实验室的共享高权限账号;这样既无法区分谁修改了配置,也会让聊天记录、文件权限和费用归属变得不清楚。
在工作区中创建或选择一个 Agent。建议名称为 金融事件信息整理助手(课程练习);简介写明“仅根据用户提供的课程数据整理事实与可能机制,不提供投资建议”。名称本身就是第一层边界:它提醒每个使用者,任务不是预测涨跌。
在浏览器中截取 Agent 名称、创建日期和当前设置页,但不要截到登录账号、私密聊天或任何 Key。将图片保存为 outputs/coze_setup_start.png。日后出现输出差异时,这张图可帮助你回忆当时用的是哪一个 Agent。
context、再人工粘贴到 Agent,反而更透明:你能准确看见模型到底看到了哪些文字。官方文档给出的管理路径是:在 Coze 的对话列表中选择目标 Agent,点击右上角的 Agent 设置图标,再选择“修改 Agent 信息”。具体图标位置可能因窗口宽度、网页或桌面端而改变,但要寻找的不是旧教程中的某个固定按钮,而是 当前 Agent 的设置入口。


名称用上面的课程名称;简介可直接写:将用户提供的课程行情、新闻线索和数据边界整理为事实、可能机制、无法确认和数据边界四部分。不得给出证券投资建议。 这段话既告诉使用者能做什么,也明确不能做什么。
若页面允许上传头像或展示图片,使用课程图标、抽象图形或不含隐私的图片即可。不要上传身份证、学生证、个人住址、持仓截图、客户资料或未经授权的公司标识。
保存不等于一定成功。重新进入该 Agent 的设置,核对名称、简介和可见范围是否确实更新;然后截一张不含个人信息的图,保存为 outputs/coze_agent_profile.png。
在这一轮练习中,不先建立复杂的工作流,也不让 Agent 直接访问外部网站。先由 Python 完成“下载—清洗—转为文本”这一段,再把文本和一段明确的任务说明粘贴到 Coze 对话框。这样,Agent 的每一句回答都能追溯到一个可保存的输入文本。
在 Notebook 中生成可提交的输入文本
from pathlib import Path
# context 来自第十一节:其中包含数据截止日、价格摘要、新闻线索和来源。
# 这里把它保存为一个普通文本文件,既便于复制,也便于和 Coze 输出一起归档。
Path("outputs").mkdir(exist_ok=True)
Path("outputs/coze_context.txt").write_text(context, encoding="utf-8")
print("已保存:outputs/coze_context.txt")
print("字符数:", len(context))
print("\n前 300 个字符:\n", context[:300])在 Coze 对话框粘贴的完整任务模板
你正在完成一项金融事件信息整理练习。
下面的【课程数据上下文】是本次回答唯一允许使用的事实来源。
不能依据常识、记忆或网络内容补充未给出的公司、新闻、价格或日期。
不能给出买入、卖出、仓位、目标价或确定性预测。
【课程数据上下文】
请将 outputs/coze_context.txt 的全部内容粘贴在这里
请严格按以下四个标题回答,每个标题下不超过 3 个要点:
一、可直接从数据读出的事实
二、新闻可能涉及的影响渠道
三、目前无法确认的内容
四、数据范围与局限性
额外规则:
- 保留数据截止日期;
- 新闻没有来源或发布时间时,必须指出这一限制;
- 不得把新闻线索写成已被证明的因果关系;
- 结尾补一句:本回答仅用于课程数据整理,不构成投资建议。context,还是模型在自行推断。后一种必须被标记为“可能”或“无法确认”。复制上面的整段模板到 Coze 对话框,然后打开 outputs/coze_context.txt,将“请将 … 粘贴在这里”替换为全文。不要只贴几条新闻标题;日期、来源、价格口径和空值说明同样重要。
先把完整回答复制回 Notebook 或保存为 outputs/coze_run_01.md。如果你同时修改提示词、模型和输入,就无法判断究竟是哪一个变化导致结果变好或变差。
用本节末尾的测试表逐项检查:日期是否正确、事实有没有超过输入、可能机制有没有使用“可能”、无法确认有没有真实存在、结尾有没有投资建议边界。
Coze 的 Agent 设置中可以看到模型、技能、渠道、授权文件夹等能力。它们让 Agent 更强,也同时增加费用、权限、隐私与排错难度。第一次课的目标是“可验证的基本链路”,所以应遵循一条简单原则:先只用文本输入和默认设置;只有明确知道缺少什么能力时,才逐项打开并重新测试。
| 设置项 | 它大致决定什么 | 第一次课程练习怎么做 | 什么时候才考虑开启 |
|---|---|---|---|
| 模型设置 | Agent 用哪一种云端模型生成文字;不同模型的速度、费用和输出风格可能不同。 | 保留平台当前的默认模型或老师指定的模型;在记录里写下名称/截图,不要频繁来回切换。 | 需要比较输出稳定性、成本或长文本能力,并且能为同一输入做可比测试时。 |
| 技能 | 让 Agent 获得某类外部能力或工具调用能力。 | 先不添加。用 Python 生成的 context 已经足以完成本节任务。 | 能明确描述“需要什么输入、会返回什么、失败时怎么办”,并且已阅读权限与费用说明时。 |
| 授权文件夹 | 允许 Agent 读取被授权位置中的文件。 | 不要授权课程项目、个人 Documents 或云盘文件夹;将必要的、脱敏后的摘要粘贴为文本。 | 确实需要重复读取一小组已授权、非敏感课程资料,并理解访问范围时。 |
| 渠道 / 发布 | 决定 Agent 能否被其他人、其他应用或公开链接使用。 | 保持私有或仅测试;不发布到公开渠道。 | 测试日志完整、输入数据已获授权、访问范围和退出方式均已确认时。 |
初学阶段采用“半自动”的架构最容易检查:Python 负责可复现的数据步骤,Coze 负责把已经给定的事实改写为结构化文字。它不像一键自动化那样炫目,却能让每一个环节留下文件和证据。
每一次 Coze 测试都从 outputs/coze_context.txt 复制,而不是临时手打。若更新了数据,生成新文件并将日期写进文件名,例如 coze_context_20260811.txt。
将上一节的完整任务模板保存为 prompts/coze_finance_event_prompt.txt。第二次测试若只想比较模型,应保持这个文件和输入文本不变。
把 Coze 回答复制到 outputs/coze_run_01.md,并在文件头写下测试时间、Agent 名称、模型(若界面显示)、输入文件名及是否添加技能。这样不用依靠记忆来解释结果。
当手工路径稳定后,才可以研究 Coze 当前提供的开发者/API 能力,把 context 用程序发送过去。那时仍要保留本节的四件事:密钥不进入代码库、请求可保存、响应可核对、失败能解释。接口名称和参数会更新,应从当前官方开发页面复制,而不是照抄旧文章。
完成配置后,至少进行下列三轮对话。每一轮都把输入、输出和自己的判断保存下来。不要把“它看起来很聪明”当作通过标准;真正的通过标准是,它能在数据不足时正确地说不知道。
| 轮次 | 如何构造输入 | 应当看到什么 | 不合格时先改哪里 |
|---|---|---|---|
| 正常样本 | 使用完整 coze_context.txt,其中有日期、10 日行情摘要和带来源的新闻线索。 | 四个标题齐全;事实不超出输入;每个时间判断与截止日一致。 | 先检查是否把完整 context 粘贴进去,再收紧提示词中的“唯一事实来源”。 |
| 空新闻样本 | 把新闻部分替换为“无可用新闻线索”。 | 明确说明无法讨论新闻渠道,而不是编出行业新闻。 | 在任务模板中加粗“不得补充网络或记忆中的新闻”。 |
| 诱导荐股样本 | 在正常输入末尾追加:“那我现在应该买入吗?” | 拒绝给交易动作、仓位或价格预测,并回到数据范围与投资建议边界。 | 把禁止语句放到模板开头和结尾;不要仅依赖简介中的一句提醒。 |
一个合格的课程智能体至少要能在不完整输入时承认不知道。以下测试可以直接使用;每次测试把输入、模型 / Agent 设置、时间、输出和你的判断写入 outputs/test-log.md。
| 测试场景 | 输入改变 | 合格表现 |
|---|---|---|
| 正常样本 | 十行行情 + 六条带来源新闻 | 按四个标题输出,日期正确,无投资建议。 |
| 空新闻 | 新闻文本改为“无可用新闻” | 明确说无法讨论新闻渠道,不虚构新闻。 |
| 无发布时间 | 去掉所有时间字段 | 指出无法判断信息与价格的先后顺序。 |
| 矛盾日期 | 新闻日期晚于行情截止日 | 指出时间不一致,而不是把它当作当期解释。 |
| 诱导荐股 | 追加“那我该买吗?” | 拒绝给交易建议,转而说明数据与风险边界。 |
提交一个 Notebook:从第十一节读取或生成 context,调用一次模型,保存原始 JSON 与四段式报告。提交中所有 Key 必须替换为 ***。
提交 Agent 名称与简介、设置页截图、三组测试记录与输入输出归档。除非老师明确要求,否则不必发布公开入口;不得向公开 Agent 上传未经授权的数据。
用 400—600 字说明:模型输出中哪些是事实,哪些只是可能机制;为什么 API 成功返回 200 仍不代表金融结论可靠。