LLM 驱动的新闻策展流程
适用场景
需要定时发布多个内容批次(如早报+晚报),且要求:
- 每批内容不重复
- 内容按类别均衡(如行业突发/新品发布/技术落地各一条)
- 自动筛选高质量新闻(排除软文/广告/低价值内容)
核心流程
1. 采集大池子 (20-30条原始新闻)
2. LLM 评分+分类 → JSON 数组
3. 按批次选取 (早报=top3, 晚报=次3条)
4. LLM 改写为最终格式
Step 1: 新闻采集
从多个 RSS 源采集,去重后保留:
import requests
from bs4 import BeautifulSoup
import xml.etree.ElementTree as ET
def scrape_rss(url, limit=15):
r = requests.get(url, headers={"User-Agent": "Mozilla/5.0 ..."}, timeout=15)
root = ET.fromstring(r.content)
items = []
for entry in root.iter("item"):
title = entry.find("title").text or ""
link = entry.find("link").text or ""
desc = re.sub(r"<[^>]+>", "", entry.find("description").text or "")
items.append({"title": title.strip(), "summary": desc[:200], "url": link})
if len(items) >= limit:
break
return items
去重:用标题前15字符作为 key。
Step 2: LLM 评分分类
将所有新闻发给 LLM,让它评分(1-10)并分类:
PROMPT = """你是新闻主编。对以下新闻评分并分类(只输出JSON)。
评分(1-10):10=重大突发事件, 8-9=重磅, 6-7=有话题性, 4-5=一般, 1-3=软文
分类:{分类列表}
素材:
{编号列表}
输出JSON数组,每个元素只包含4个字段:
[{{"idx":序号,"category":"分类","score":分数,"t":"标题前10字"}}, ...]
按score降序。"""
关键优化:
- prompt 中只要求输出 idx/category/score/t 四个字段(不要完整 title/reason),节省 token
- max_tokens=2000(29条新闻的 JSON 约1700字符)
- 解析时截断到最后一个 ] 以容忍不完整 JSON
def parse_scored_json(result, original_items):
clean = re.sub(r"```json\s*|\s*```", "", result).strip()
last_bracket = clean.rfind("]")
if last_bracket > 0:
clean = clean[:last_bracket + 1]
data = json.loads(clean)
# 补上原始数据
for item in data:
idx = item["idx"]
if 1 <= idx <= len(original_items):
item["title"] = original_items[idx-1]["title"]
item["summary"] = original_items[idx-1].get("summary", "")
return data
Step 3: 批次选取(避免重叠)
def select_for_batch(scored, batch="first", count=3):
categories = ["行业突发", "新品发布", "技术落地"] # 每个类别至少一条
result = []
used = set()
# 第一轮:每个类别选一条最高分
for cat in categories:
for item in scored:
if item["idx"] not in used and item["category"] == cat:
result.append(item)
used.add(item["idx"])
break
# 第二轮:补齐
for item in scored:
if len(result) >= count:
break
if item["idx"] not in used:
result.append(item)
used.add(item["idx"])
# 第二批次:排除第一批已用的
if batch == "second":
first_used = {item["idx"] for item in result}
second = []
second_used = set()
for cat in categories:
for item in scored:
if item["idx"] not in first_used and item["idx"] not in second_used and item["category"] == cat:
second.append(item)
second_used.add(item["idx"])
break
for item in scored:
if len(second) >= count:
break
if item["idx"] not in first_used and item["idx"] not in second_used:
second.append(item)
second_used.add(item["idx"])
result = second
return result[:count]
Step 4: LLM 改写
将选中的新闻发给 LLM 改写为最终格式:
REWRITE_PROMPT = """将以下新闻改写为{count}条精简快讯。
要求:
1. 每条对应一个类别:{类别列表}
2. 每条严格{字数}字
3. 语言简洁,去除emoji和营销话术
4. 每条以【类别】开头
新闻素材:
{素材}
输出格式:
【类别】xxx
【类别】xxx
..."""
平台风控措辞红线
在中国社交平台(小红书/抖音/微博)发布股票/投资相关内容时:
绝对禁止:推荐、买入、卖出、建仓、加仓、看涨、看跌、目标价、涨幅预测、稳赚、必涨、上车、抄底、割肉
安全替代:
- "关注" 代替 "买入"
- "动态" 代替 "利好利空"
- "值得留意" 代替 "建议"
- 只陈述事实,不做评价
- 结尾加声明:"以上内容整理自公开资讯,仅供信息参考,不涉及任何投资建议。"
格式建议:
【本周回顾】
板块名
• 事实描述(无评价)
【下周留意】
• 事件名|中性说明
声明:以上内容整理自公开资讯,仅供信息参考,不涉及任何投资建议。
关键注意事项
- LLM JSON 输出截断:新闻条数多时 JSON 可能被截断。用
max_tokens=2000+ 截断到最后]容错 - 新闻质量差异大:RSS 源可能返回软文/广告。评分 1-3 分的应直接排除
- 类别均衡:选取算法优先保证每个类别至少一条,再补齐剩余名额
- 缓存策略:如果早报和晚报间隔几小时,建议缓存评分结果到文件,晚报直接读取而非重新评分(新闻源可能已更新)