diff --git a/pipeline_opportunity/opp_ability.py b/pipeline_opportunity/opp_ability.py index e5e6f93..9cedfeb 100644 --- a/pipeline_opportunity/opp_ability.py +++ b/pipeline_opportunity/opp_ability.py @@ -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 链接,外链会自动新窗口打开)。 diff --git a/pipeline_opportunity/opp_data_capability.py b/pipeline_opportunity/opp_data_capability.py index 61dbd4e..c3a9cb6 100644 --- a/pipeline_opportunity/opp_data_capability.py +++ b/pipeline_opportunity/opp_data_capability.py @@ -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="",