fix(opp): 统计聚合优先+明细limit硬上限——_clamp_detail_limit(50上限,默认20/10);category_references/demands/overseas_references默认limit 500/50→20/10;工具描述改『统计首选hot_*/明细只取样例limit≤10』;OPP_PROMPT硬规则补统计聚合优先+平均价=total_budget/count公式;根治prompt原指引『给排名统计调category_references取分项明细』诱导agent拉300条全量明细撑爆上下文

This commit is contained in:
yumoqing 2026-09-11 13:46:28 +08:00
parent 2f71d851ef
commit 8c5bf498c8
2 changed files with 48 additions and 20 deletions

View File

@ -49,20 +49,20 @@ OPP_TOOLS = [
parameters={"tender_id": "招标信息ID"}, category="data"),
ToolDefinition(name="opp_crawler_stats", description="查看数据爬取平台采集健康度(总量/24h新增/最近运行)",
parameters={}, category="data"),
ToolDefinition(name="opp_category_references", description="查某软件主题的全部分项明细(references 可查证:每条带公告原文URL+采集来源)。回答热点/排名类问题时用本工具取分项并附来源链接",
ToolDefinition(name="opp_category_references", description="查某软件主题的分项明细(每条带公告原文URL+采集来源,供逐条查证/举例)。⚠️ 明细是「举例佐证」用的,不是「统计」用的——排名/数量/金额统计先用 opp_hot_software(已返回 tender_count+total_budget_wan),只在需要给2~5个样例链接时才调本工具且 limit≤10",
parameters={"category": "软件主题名(须与热点排名中的category一致)",
"days": "统计窗口天数(默认30)", "limit": "条数(默认200)"}, category="data"),
ToolDefinition(name="opp_demands", description="查众包平台软件需求发布列表——甲方直接发布的开发需求,覆盖国内(猪八戒zbj/一品威客epwk)与海外(Freelancer.com freelancer/PeoplePerHour pph)。每条带详情页URL可查证",
parameters={"keyword": "标题关键词(可选)", "days": "统计窗口天数(默认30)",
"days": "统计窗口天数(默认30)", "limit": "条数(默认20,最大50——只取样例不要拉全量)"}, category="data"),
ToolDefinition(name="opp_demands", description="查众包平台需求明细列表(国内猪八戒zbj/一品威客epwk + 海外freelancer/pph,每条带详情页URL可查证)。⚠️ 主题排名/数量/金额统计先用 opp_hot_demands(国内)/opp_hot_overseas(海外)——它们已聚合好排名;本工具只用于按关键词找具体需求样例,limit≤10",
parameters={"keyword": "标题关键词(建议必填以缩小范围)", "days": "统计窗口天数(默认30)",
"source": "来源(可选: zbj猪八戒/epwk一品威客/freelancer海外/pph海外,不传=全部)",
"limit": "条数(默认50)"}, category="data"),
ToolDefinition(name="opp_hot_demands", description="国内众包需求热点主题排名(需求侧热度,与招标侧的 opp_hot_software 互补)",
"limit": "条数(默认10,最大50)"}, category="data"),
ToolDefinition(name="opp_hot_demands", description="【统计首选】国内众包需求热点主题排名——直接返回各主题需求数量(tender_count)与预算合计(total_budget_wan)+样例,无需拉明细自己数。与招标侧 opp_hot_software 互补",
parameters={"days": "统计窗口天数(默认30)", "top": "Top条数(默认10)"}, category="data"),
ToolDefinition(name="opp_hot_overseas", description="海外软件需求热点主题排名(Freelancer.com/PeoplePerHour 众包需求,英文标题按8大主题归类:AI智能体/Web/移动/桌面企业软件/数据集成/自动化/DevOps云/游戏)。用户问国外/海外市场、国外软件需求前十时用本工具",
ToolDefinition(name="opp_hot_overseas", description="【统计首选】海外众包需求热点主题排名(Freelancer/PeoplePerHour,英文标题按8大主题归类)——直接返回各主题数量+预算合计+按来源分布,无需拉明细自己数。用户问国外/海外市场、中外众包排名时用本工具",
parameters={"days": "统计窗口天数(默认30)", "top": "Top条数(默认10)"}, category="data"),
ToolDefinition(name="opp_overseas_references", description="查某海外需求主题的全部分项明细(references 可查证:每条带Freelancer/PeoplePerHour详情页URL)。回答海外热点问题时用本工具取分项并附来源链接",
ToolDefinition(name="opp_overseas_references", description="查某海外需求主题的分项明细(每条带Freelancer/PeoplePerHour详情页URL,供逐条查证/举例)。⚠️ 统计先用 opp_hot_overseas(已返回 tender_count+total_budget_wan+by_source),只在需要2~5个样例链接时才调本工具且 limit≤10",
parameters={"category": "海外主题名(须与 opp_hot_overseas 排名中的category一致)",
"days": "统计窗口天数(默认30)", "limit": "条数(默认200)"}, category="data"),
"days": "统计窗口天数(默认30)", "limit": "条数(默认20,最大50——只取样例不要拉全量)"}, category="data"),
# ── 报告与审批(商机闭环)──
ToolDefinition(name="opp_create_report", description="创建软件研发报告草稿。从热门软件中选定的方向写入报告,数据基础章节自动从爬取平台拉取。正文必须按四节模板组织(## 研发场景 / ## 输入 / ## 输出 / ## 成果),商店详情页按节展示",
@ -129,11 +129,17 @@ opp_create_report / opp_update_report 的正文必须用以下四个二级标题
旧格式(无四节标题)的存量报告仍可查看,全文归入「输出」节展示。
## 硬规则
- **统计优先用聚合工具,明细只取样例(2026-09-11 实测教训)**:
数量/排名/预算合计/平均价这类**统计**一律用聚合工具——opp_hot_software(招标侧)、
opp_hot_demands(国内众包)、opp_hot_overseas(海外众包)、opp_query_tenders(group_by=...),
它们已直接返回 tender_count / total_budget_wan,**不要**拉全量明细自己数。
明细类工具(opp_category_references / opp_demands / opp_overseas_references)只用于
给 2~5 条代表性样例佐证,limit 取 10 以内(机制层有硬上限,拉全量会被截断)。
平均价格 = total_budget_wan / tender_count(聚合值自算,勿逐条累加)。
- 报告里的招标数量、预算、项目案例必须来自工具返回的真实数据,**禁止编造**;
查不到就如实写"数据未覆盖"。
- **所有分析必须带 references(可查证)**:给排名/统计/推荐结论时,调
opp_category_references / opp_query_tenders / opp_demands / opp_overseas_references
取分项明细,回答末尾附 References 章节——
- **所有分析必须带 references(可查证)**:给排名/统计/推荐结论时,先用聚合工具拿统计值,
再用明细工具取 **2~5 条代表性分项**(limit≤10)作样例佐证,回答末尾附 References 章节——
列出自带的「📋 数据参考」菜单(招标/国内众包需求/海外需求三类主题:点主题条目弹出
全部分项,点分项条目弹出具体内容——公告/需求全文与附件下载,数据均来自爬取平台),
并在正文中给出 3-5 条代表性分项的标题+来源链接(markdown 链接,外链会自动新窗口打开)。

View File

@ -6,6 +6,24 @@
from .opp_common import crawler_get
# 明细类工具的 limit 硬上限(2026-09-11):明细是「举例佐证」用,不是「统计」用。
# 实测 agent 为「数排名前三/算平均价」拉 category_references(limit=300) 等全量明细,
# 单次 ~2 万字符,连调多次撑爆上下文导致会话超时失败。统计应走聚合工具
#(hot_demands/hot_overseas/hot_software 已返回 tender_count+total_budget_wan)。
# 这是代码硬门禁,不靠工具描述让 LLM 自觉(描述只作引导)。
_DETAIL_LIMIT_MAX = 50
def _clamp_detail_limit(limit, default=20):
"""把明细类工具的 limit 收敛到 [1, _DETAIL_LIMIT_MAX],缺省用 default。"""
try:
n = int(float(limit))
except (TypeError, ValueError):
n = default
if n <= 0:
n = default
return min(n, _DETAIL_LIMIT_MAX)
async def search_tenders(sor, keyword="", days=7, source="", only_it=True, limit=50):
"""关键词检索招标信息。"""
@ -37,14 +55,16 @@ async def hot_software(sor, days=30, top=10):
{"days": days, "top": top})
async def category_references(sor, category, days=30, limit=500, record_type="tender"):
"""某软件主题的全部分项(references 可查证)。
async def category_references(sor, category, days=30, limit=20, record_type="tender"):
"""某软件主题的分项明细(references 可查证,举例佐证用)。
每条带公告原文/详情页 url + 采集来源 source_url,供界面逐条查证。
record_type: tender=招标(默认) / demand=众包需求发布(猪八戒/一品威客)。
limit 硬上限 _DETAIL_LIMIT_MAX(50)——统计用 hot_software 聚合,勿拉全量明细。
"""
return await crawler_get(sor, "/api/category_references",
{"category": category, "days": days, "limit": limit,
{"category": category, "days": days,
"limit": _clamp_detail_limit(limit),
"record_type": record_type})
@ -53,13 +73,13 @@ async def crawler_stats(sor):
return await crawler_get(sor, "/api/stats")
async def demands(sor, keyword="", days=30, source="", limit=50):
async def demands(sor, keyword="", days=30, source="", limit=10):
"""众包平台软件需求发布列表(国内:猪八戒/一品威客;海外:Freelancer/PeoplePerHour)。
区别于招标:这些是甲方在众包平台直接发布的开发需求,
反映市场真实需求热度与预算分布。每条带详情页 url(可查证)。
"""
params = {"days": days, "limit": limit}
params = {"days": days, "limit": _clamp_detail_limit(limit)}
if keyword:
params["keyword"] = keyword
if source:
@ -79,13 +99,15 @@ async def hot_overseas(sor, days=30, top=10):
{"days": days, "top": top})
async def overseas_references(sor, category, days=30, limit=500):
"""某海外需求主题的全部分项(references 可查证)。
async def overseas_references(sor, category, days=30, limit=20):
"""某海外需求主题的分项明细(references 可查证,举例佐证用)。
每条带海外平台详情页 url,供界面逐条查证。
limit 硬上限 _DETAIL_LIMIT_MAX(50)——统计用 hot_overseas 聚合,勿拉全量明细。
"""
return await crawler_get(sor, "/api/overseas_references",
{"category": category, "days": days, "limit": limit})
{"category": category, "days": days,
"limit": _clamp_detail_limit(limit)})
async def query_tenders(sor, keyword="", region="", buyer="", notice_type="",