feihong-code 8.0.0 → 8.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +193 -193
- package/CHANGELOG.md +140 -117
- package/README.md +656 -636
- package/agent-team/.env.example +13 -0
- package/agent-team/README.md +42 -0
- package/agent-team/agents/__init__.py +0 -0
- package/agent-team/agents/l1_acquisition.py +207 -0
- package/agent-team/agents/l2_content.py +237 -0
- package/agent-team/agents/l3_conversion.py +148 -0
- package/agent-team/agents/l4_analysis.py +118 -0
- package/agent-team/agents/l5_management.py +52 -0
- package/agent-team/agents/registry.py +60 -0
- package/agent-team/config.py +39 -0
- package/agent-team/core/__init__.py +0 -0
- package/agent-team/core/agent.py +73 -0
- package/agent-team/core/models.py +347 -0
- package/agent-team/core/scheduler.py +150 -0
- package/agent-team/core/task.py +121 -0
- package/agent-team/feihongzhi.db +0 -0
- package/agent-team/llm/__init__.py +12 -0
- package/agent-team/llm/base.py +22 -0
- package/agent-team/llm/doubao_llm.py +52 -0
- package/agent-team/llm/mock_llm.py +42 -0
- package/agent-team/main.py +235 -0
- package/agent-team/requirements.txt +2 -0
- package/agent-team/skill_packager.py +248 -0
- package/agent-team/skills/01_AI/350/216/267/345/256/242/347/272/277/347/264/242/351/233/267/350/276/276/SKILL.md +40 -0
- package/agent-team/skills/01_AI/350/216/267/345/256/242/347/272/277/347/264/242/351/233/267/350/276/276/run.py +111 -0
- package/agent-team/skills/02_AI/351/224/200/345/224/256/350/267/237/350/277/233/351/224/200/345/206/240/SKILL.md +38 -0
- package/agent-team/skills/02_AI/351/224/200/345/224/256/350/267/237/350/277/233/351/224/200/345/206/240/run.py +108 -0
- package/agent-team/skills/03_/350/257/204/350/256/272/345/214/272/345/225/206/346/234/272/350/257/206/345/210/253/345/256/230/SKILL.md +38 -0
- package/agent-team/skills/03_/350/257/204/350/256/272/345/214/272/345/225/206/346/234/272/350/257/206/345/210/253/345/256/230/run.py +106 -0
- package/agent-team/skills/04_/345/256/242/346/210/267/350/201/212/345/244/251/346/210/220/344/272/244/345/210/206/346/236/220/345/256/230/SKILL.md +37 -0
- package/agent-team/skills/04_/345/256/242/346/210/267/350/201/212/345/244/251/346/210/220/344/272/244/345/210/206/346/236/220/345/256/230/run.py +107 -0
- package/agent-team/skills/05_/345/220/214/350/241/214/347/210/206/346/254/276/351/233/267/350/276/276/SKILL.md +38 -0
- package/agent-team/skills/05_/345/220/214/350/241/214/347/210/206/346/254/276/351/233/267/350/276/276/run.py +99 -0
- package/agent-team/skills/06_/346/257/217/346/227/245/347/262/276/345/207/206/350/216/267/345/256/242/351/200/211/351/242/230/345/256/230/SKILL.md +39 -0
- package/agent-team/skills/06_/346/257/217/346/227/245/347/262/276/345/207/206/350/216/267/345/256/242/351/200/211/351/242/230/345/256/230/run.py +103 -0
- package/agent-team/skills/07_AI/345/244/226/350/264/270/345/274/200/345/217/221/345/256/242/346/210/267/345/221/230/345/267/245/SKILL.md +39 -0
- package/agent-team/skills/07_AI/345/244/226/350/264/270/345/274/200/345/217/221/345/256/242/346/210/267/345/221/230/345/267/245/run.py +103 -0
- package/agent-team/skills/08_/345/260/217/347/272/242/344/271/246/347/262/276/345/207/206/350/216/267/345/256/242/345/221/230/345/267/245/SKILL.md +40 -0
- package/agent-team/skills/08_/345/260/217/347/272/242/344/271/246/347/262/276/345/207/206/350/216/267/345/256/242/345/221/230/345/267/245/run.py +97 -0
- package/agent-team/skills/09_/347/247/201/345/237/237/345/256/242/346/210/267/345/210/206/345/261/202/350/267/237/350/277/233/345/256/230/SKILL.md +38 -0
- package/agent-team/skills/09_/347/247/201/345/237/237/345/256/242/346/210/267/345/210/206/345/261/202/350/267/237/350/277/233/345/256/230/run.py +106 -0
- package/agent-team/skills/10_GEO/345/225/206/346/234/272/350/257/212/346/226/255/345/256/230/SKILL.md +38 -0
- package/agent-team/skills/10_GEO/345/225/206/346/234/272/350/257/212/346/226/255/345/256/230/run.py +108 -0
- package/agent-team/skills/11_/344/270/200/344/272/272/345/205/254/345/217/270AI/345/221/230/345/267/245/350/260/203/345/272/246/345/256/230/SKILL.md +37 -0
- package/agent-team/skills/11_/344/270/200/344/272/272/345/205/254/345/217/270AI/345/221/230/345/267/245/350/260/203/345/272/246/345/256/230/run.py +111 -0
- package/agent-team/skills/12_/350/200/201/346/235/277/347/237/255/350/247/206/351/242/221/350/216/267/345/256/242/350/204/232/346/234/254/345/256/230/SKILL.md +39 -0
- package/agent-team/skills/12_/350/200/201/346/235/277/347/237/255/350/247/206/351/242/221/350/216/267/345/256/242/350/204/232/346/234/254/345/256/230/run.py +104 -0
- package/agent-team/skills/13_/345/215/232/344/270/273/350/264/246/345/217/267/346/267/261/345/272/246/346/213/206/350/247/243/345/256/230/SKILL.md +37 -0
- package/agent-team/skills/13_/345/215/232/344/270/273/350/264/246/345/217/267/346/267/261/345/272/246/346/213/206/350/247/243/345/256/230/run.py +105 -0
- package/agent-team/skills/14_AI/347/237/255/350/247/206/351/242/221/350/207/252/345/212/250/345/211/252/350/276/221/345/270/210/SKILL.md +39 -0
- package/agent-team/skills/14_AI/347/237/255/350/247/206/351/242/221/350/207/252/345/212/250/345/211/252/350/276/221/345/270/210/run.py +108 -0
- package/agent-team/skills/15_/345/205/254/344/274/227/345/217/267/350/207/252/345/212/250/350/277/220/350/220/245/345/217/221/345/270/203/345/256/230/SKILL.md +38 -0
- package/agent-team/skills/15_/345/205/254/344/274/227/345/217/267/350/207/252/345/212/250/350/277/220/350/220/245/345/217/221/345/270/203/345/256/230/run.py +105 -0
- package/agent-team/skills/16_/350/241/214/344/270/232/346/267/261/345/272/246/345/210/206/346/236/220/345/270/210/SKILL.md +38 -0
- package/agent-team/skills/16_/350/241/214/344/270/232/346/267/261/345/272/246/345/210/206/346/236/220/345/270/210/run.py +108 -0
- package/agent-team/skills/17_/346/212/225/350/265/204/347/240/224/347/251/266/345/222/250/350/257/242/345/256/230/SKILL.md +38 -0
- package/agent-team/skills/17_/346/212/225/350/265/204/347/240/224/347/251/266/345/222/250/350/257/242/345/256/230/run.py +106 -0
- package/agent-team/tests/__init__.py +0 -0
- package/agent-team/tests/test_core.py +156 -0
- package/dist/agent/agent-session.js +103 -0
- package/dist/agent/agent-session.js.map +1 -0
- package/dist/agent/orchestrator.js +8 -0
- package/dist/agent/orchestrator.js.map +1 -1
- package/dist/agent/steer.js +52 -0
- package/dist/agent/steer.js.map +1 -0
- package/dist/cli/index.js +1 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/node-guard.js +17 -0
- package/dist/cli/node-guard.js.map +1 -0
- package/dist/cli/run.js +2 -0
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/version.js +1 -1
- package/dist/enterprise/policy.js +40 -17
- package/dist/enterprise/policy.js.map +1 -1
- package/dist/tools/agents/agents-bridge.js +144 -0
- package/dist/tools/agents/agents-bridge.js.map +1 -0
- package/dist/tools/desktop/desktop-guard.js +81 -0
- package/dist/tools/desktop/desktop-guard.js.map +1 -0
- package/dist/tools/desktop/desktop.tool.js +201 -0
- package/dist/tools/desktop/desktop.tool.js.map +1 -0
- package/dist/tools/desktop/feihong-win.js +163 -0
- package/dist/tools/desktop/feihong-win.js.map +1 -0
- package/dist/tools/desktop/index.js +37 -0
- package/dist/tools/desktop/index.js.map +1 -0
- package/dist/tools/index.js +2 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/mcp/index.js +10 -2
- package/dist/tools/mcp/index.js.map +1 -1
- package/dist/tools/mcp/mcp-client.js +4 -0
- package/dist/tools/mcp/mcp-client.js.map +1 -1
- package/dist/tools/sandbox.js +28 -0
- package/dist/tools/sandbox.js.map +1 -1
- package/dist/web/public/public/css/style.css +1756 -0
- package/dist/web/public/public/favicon.svg +11 -0
- package/dist/web/public/public/index.html +1246 -0
- package/dist/web/public/public/js/api.js +558 -0
- package/dist/web/public/public/js/app.js +2233 -0
- package/dist/web/public/public/js/mock-api.js +259 -0
- package/dist/web/public/public/js/monaco-editor.js +363 -0
- package/dist/web/public/public/js/ui.js +2217 -0
- package/dist/web/public/public/js/utils.js +214 -0
- package/dist/web/public/public/manifest.json +59 -0
- package/dist/web/public/public/robots.txt +14 -0
- package/dist/web/public/public/service-worker.js +149 -0
- package/docs/AI/345/221/230/345/267/245/345/206/233/345/233/242-/346/225/264/345/220/210/350/257/264/346/230/216.md +68 -0
- package/docs/API.md +1 -1
- package/docs/App/346/212/200/346/234/257/350/257/264/346/230/216/344/271/246.md +3 -3
- package/docs/P1.1-P3-P5/345/267/245/347/250/213/345/256/236/346/226/275/346/200/273/347/273/223.md +328 -0
- package/docs/P5-Pi/345/257/271/347/205/247/350/257/204/346/265/213/346/212/245/345/221/212-mock/346/250/241/345/274/217.json +125 -0
- package/docs/P5-Pi/345/257/271/347/205/247/350/257/204/346/265/213/346/212/245/345/221/212-/347/234/237/345/256/236/346/250/241/345/236/213.json +138 -0
- package/docs/P5-pi-compare-real-report.json +138 -0
- package/docs/P5-pi-compare-report.json +125 -0
- package/docs/Pi-Agent/346/216/245/345/205/245/351/243/236/350/231/271Code-MVP/351/233/206/346/210/220/344/272/244/344/273/230/347/211/251.md +355 -0
- package/docs/Pi-Agent/346/216/245/345/205/245/351/243/236/350/231/271Code/344/273/267/345/200/274/345/210/206/346/236/220-/345/274/200/345/217/221/346/226/207/346/241/243.md +291 -0
- package/docs/Pi-Agent/346/216/245/345/205/245/351/243/236/350/231/271Code/344/273/267/345/200/274/351/207/215/344/274/260-/345/217/257/350/247/206/345/214/226.html +84 -0
- package/docs/SWE-bench-300-agnes-2.5-flash-/346/234/200/347/273/210/346/212/245/345/221/212.json +2012 -0
- package/docs/SWE-bench-300-agnes-2.5-flash-/350/267/221/345/210/206/346/212/245/345/221/212.md +74 -0
- package/docs/SWE-bench-Lite-DeepSeek-V4-Flash-/350/267/221/345/210/206/346/212/245/345/221/212.md +102 -0
- package/docs/TECHNICAL-SPECIFICATION.md +66 -0
- package/docs/TECHNICAL-SPECIFICATION.pdf +0 -0
- package/docs/Windows/346/211/213/350/204/232-POC/346/274/224/347/244/272/350/204/232/346/234/254.md +131 -0
- package/docs/Windows/346/211/213/350/204/232/346/216/245/345/205/245/346/214/207/345/215/227.md +181 -0
- package/docs//344/275/277/347/224/250/350/257/264/346/230/216/344/271/246-v8.0.1.md +146 -0
- package/docs//344/275/277/347/224/250/350/257/264/346/230/216/344/271/246.md +1 -1
- package/package.json +6 -3
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""豆包大模型适配器(火山方舟 OpenAI 兼容接口)。
|
|
2
|
+
|
|
3
|
+
零第三方依赖:使用标准库 urllib 发起请求。
|
|
4
|
+
配置:DOUBAO_API_KEY / DOUBAO_MODEL / DOUBAO_BASE_URL(见 config.py)。
|
|
5
|
+
"""
|
|
6
|
+
import json
|
|
7
|
+
import urllib.request
|
|
8
|
+
import urllib.error
|
|
9
|
+
from typing import Any, Dict, List
|
|
10
|
+
|
|
11
|
+
from llm.base import LLMClient
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class DoubaoLLM(LLMClient):
|
|
15
|
+
provider = "doubao"
|
|
16
|
+
|
|
17
|
+
def __init__(self, api_key: str, model: str, base_url: str):
|
|
18
|
+
if not api_key:
|
|
19
|
+
raise ValueError("DOUBAO_API_KEY 未配置:请在 .env 中填写后设置 LLM_PROVIDER=doubao")
|
|
20
|
+
self.api_key = api_key
|
|
21
|
+
self.model = model
|
|
22
|
+
self.base_url = base_url.rstrip("/")
|
|
23
|
+
|
|
24
|
+
def chat(self, messages: List[Dict[str, str]], **kwargs: Any) -> str:
|
|
25
|
+
payload = {
|
|
26
|
+
"model": self.model,
|
|
27
|
+
"messages": messages,
|
|
28
|
+
"temperature": kwargs.get("temperature", 0.7),
|
|
29
|
+
"max_tokens": kwargs.get("max_tokens", 2048),
|
|
30
|
+
}
|
|
31
|
+
req = urllib.request.Request(
|
|
32
|
+
f"{self.base_url}/chat/completions",
|
|
33
|
+
data=json.dumps(payload).encode("utf-8"),
|
|
34
|
+
headers={
|
|
35
|
+
"Content-Type": "application/json",
|
|
36
|
+
"Authorization": f"Bearer {self.api_key}",
|
|
37
|
+
},
|
|
38
|
+
method="POST",
|
|
39
|
+
)
|
|
40
|
+
try:
|
|
41
|
+
with urllib.request.urlopen(req, timeout=kwargs.get("timeout", 60)) as resp:
|
|
42
|
+
body = json.loads(resp.read().decode("utf-8"))
|
|
43
|
+
except urllib.error.HTTPError as e:
|
|
44
|
+
detail = e.read().decode("utf-8", errors="ignore")
|
|
45
|
+
raise RuntimeError(f"豆包 API 调用失败 HTTP {e.code}: {detail[:300]}") from e
|
|
46
|
+
except urllib.error.URLError as e:
|
|
47
|
+
raise RuntimeError(f"豆包 API 网络错误: {e.reason}") from e
|
|
48
|
+
|
|
49
|
+
try:
|
|
50
|
+
return body["choices"][0]["message"]["content"].strip()
|
|
51
|
+
except (KeyError, IndexError, TypeError) as e:
|
|
52
|
+
raise RuntimeError(f"豆包 API 返回结构异常: {str(body)[:300]}") from e
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""本地 Mock LLM:无 API Key 时提供确定性输出,用于跑通全链路与测试。
|
|
2
|
+
|
|
3
|
+
真实接入:设置 LLM_PROVIDER=doubao 后由 DoubaoLLM 接管。
|
|
4
|
+
"""
|
|
5
|
+
from typing import Any, Dict, List
|
|
6
|
+
|
|
7
|
+
from llm.base import LLMClient
|
|
8
|
+
|
|
9
|
+
_KEYWORDS: Dict[str, str] = {
|
|
10
|
+
"线索": "【Mock】已扫描目标渠道,发现 3 条高意向线索:A 公司(制造业,意向 A)、B 公司(贸易,意向 B)、C 公司(服务商,意向 B)。",
|
|
11
|
+
"跟进": "【Mock】已按话术模板发起首轮触达:问候 + 价值主张 + 邀约。客户 B 已读待回复,建议 24h 内二次跟进。",
|
|
12
|
+
"成交": "【Mock】聊天记录诊断:卡点在价格疑虑(出现 2 次)。建议话术:先量化 ROI,再用限时政策促单。",
|
|
13
|
+
"分层": "【Mock】客户分层完成:A 类 1 家(高频互动)、B 类 2 家(有意向待跟进)、C 类 3 家(冷启动)。",
|
|
14
|
+
"选题": "【Mock】今日选题 3 条:①AI 如何帮工厂老板获客;②一人公司如何养 17 个 AI 员工;③评论区商机怎么挖。",
|
|
15
|
+
"脚本": "【Mock】短视频脚本已生成:黄金 3 秒钩子 + 痛点场景 + 方案演示 + 行动号召,时长约 45 秒。",
|
|
16
|
+
"爆款": "【Mock】同行爆款雷达:近 7 天 3 条 10w+ 内容,共性 = 强反差标题 + 数字钩子 + 案例收尾。",
|
|
17
|
+
"拆解": "【Mock】对标账号拆解完成:定位(工厂老板 IP)、选题结构(3 段式)、转化路径(评论区引流)。",
|
|
18
|
+
"剪辑": "【Mock】已合成成片 1 条:3 段素材拼接 + 字幕 + 片尾 CTA,分辨率 1080p,时长 45 秒。",
|
|
19
|
+
"公众号": "【Mock】公众号文章已生成并排期:标题 + 三段式正文 + 文末引流钩子,明日 08:00 发布。",
|
|
20
|
+
"行业": "【Mock】行业分析要点:市场规模 120 亿,年增速 18%,竞争格局分散,头部集中度提升中。",
|
|
21
|
+
"投资": "【Mock】投研要点:项目商业模式成立,核心风险 = 获客成本与复购率,建议关注现金流。",
|
|
22
|
+
"GEO": "【Mock】GEO 商机诊断:目标区域 3 个高潜商圈,人口密度与消费力匹配,建议优先覆盖。",
|
|
23
|
+
"外贸": "【Mock】外贸开发信已生成:针对目标市场买家,突出产能与交期优势,附 3 家候选客户。",
|
|
24
|
+
"小红书": "【Mock】小红书笔记已生成:种草型标题 + 场景化正文 + 评论区引导话术,配图 4 张。",
|
|
25
|
+
"评论区": "【Mock】评论区扫描完成:识别 2 条求购意向,来源可回溯,已转线索。",
|
|
26
|
+
"调度": "【Mock】调度计划已生成:按优先级排列 5 个任务,预估总耗时 12 分钟。",
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class MockLLM(LLMClient):
|
|
31
|
+
provider = "mock"
|
|
32
|
+
|
|
33
|
+
def chat(self, messages: List[Dict[str, str]], **kwargs: Any) -> str:
|
|
34
|
+
last = ""
|
|
35
|
+
for m in reversed(messages):
|
|
36
|
+
if m.get("role") == "user":
|
|
37
|
+
last = m.get("content", "")
|
|
38
|
+
break
|
|
39
|
+
for kw, out in _KEYWORDS.items():
|
|
40
|
+
if kw in last:
|
|
41
|
+
return out
|
|
42
|
+
return "【Mock】已收到任务,按规则完成处理。"
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""飞虹智 · AI 员工军团系统 — 命令行入口。
|
|
4
|
+
|
|
5
|
+
命令:
|
|
6
|
+
init-db 初始化数据库
|
|
7
|
+
list-agents 查看 17 个 AI 员工清单
|
|
8
|
+
submit 提交单个任务(--module 编号 --type 类型 --input JSON)
|
|
9
|
+
run-once 执行一轮 pending 任务
|
|
10
|
+
run-loop 持续执行(--times N)
|
|
11
|
+
approve 人工确认任务(--task-id --no 表示驳回)
|
|
12
|
+
stats 任务统计
|
|
13
|
+
demo-pipeline M1 销售闭环演示(01→02→04→09)
|
|
14
|
+
export-skills 导出 17 个 Skill 包到 skills/
|
|
15
|
+
install-skills 安装 Skill 包到指定 Skill 根目录
|
|
16
|
+
"""
|
|
17
|
+
import argparse
|
|
18
|
+
import json
|
|
19
|
+
import logging
|
|
20
|
+
import sys
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
|
|
23
|
+
from config import BASE_DIR
|
|
24
|
+
|
|
25
|
+
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _get_llm():
|
|
29
|
+
from llm import get_llm
|
|
30
|
+
return get_llm()
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _get_scheduler():
|
|
34
|
+
from core import models
|
|
35
|
+
from core.scheduler import Scheduler
|
|
36
|
+
from agents.registry import instantiate_all
|
|
37
|
+
llm = _get_llm()
|
|
38
|
+
agents = instantiate_all(llm)
|
|
39
|
+
return Scheduler(agents)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def cmd_init_db(args):
|
|
43
|
+
from core import models
|
|
44
|
+
import config as cfg
|
|
45
|
+
models.init_db()
|
|
46
|
+
print("数据库已初始化:", cfg.DB_PATH)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def cmd_list_agents(args):
|
|
50
|
+
from agents.registry import list_meta
|
|
51
|
+
metas = list_meta()
|
|
52
|
+
print(f"{'编号':<4}{'模块':<22}{'层级':<5}{'优先级':<5}说明")
|
|
53
|
+
print("-" * 90)
|
|
54
|
+
for m in metas:
|
|
55
|
+
print(f"{m['module_id']:<4}{m['name']:<22}{m['layer']:<5}{m['priority']:<5}{m['description']}")
|
|
56
|
+
print(f"\n共 {len(metas)} 个 AI 员工")
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def cmd_submit(args):
|
|
60
|
+
sched = _get_scheduler()
|
|
61
|
+
data = json.loads(args.input) if args.input else {}
|
|
62
|
+
task = sched.submit(module_id=args.module, task_type=args.type,
|
|
63
|
+
input_data=data, priority=args.priority,
|
|
64
|
+
need_human=None if args.no_human_gate is False else None)
|
|
65
|
+
print(json.dumps({"ok": True, "task_id": task.task_id, "status": task.status.value,
|
|
66
|
+
"need_human": task.need_human}, ensure_ascii=False))
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def cmd_run_once(args):
|
|
70
|
+
sched = _get_scheduler()
|
|
71
|
+
results = sched.run_once(limit=args.limit)
|
|
72
|
+
for r in results:
|
|
73
|
+
print(json.dumps(r, ensure_ascii=False))
|
|
74
|
+
print(f"\n共执行 {len(results)} 个任务")
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def cmd_run_loop(args):
|
|
78
|
+
sched = _get_scheduler()
|
|
79
|
+
for i in range(args.times):
|
|
80
|
+
n = len(sched.run_once(limit=args.limit))
|
|
81
|
+
print(f"第 {i + 1} 轮执行 {n} 个任务")
|
|
82
|
+
if n == 0:
|
|
83
|
+
break
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def cmd_approve(args):
|
|
87
|
+
sched = _get_scheduler()
|
|
88
|
+
result = sched.approve(args.task_id, approved=not args.no)
|
|
89
|
+
print(json.dumps(result, ensure_ascii=False))
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def cmd_stats(args):
|
|
93
|
+
from core import models
|
|
94
|
+
sched = _get_scheduler()
|
|
95
|
+
st = sched.stats()
|
|
96
|
+
print("任务状态分布:", json.dumps(st["task_counts"], ensure_ascii=False))
|
|
97
|
+
print("各模块任务数:", json.dumps(st["by_module"], ensure_ascii=False))
|
|
98
|
+
print(f"在线模块数: {st['agents_online']},失败重试上限: {st['max_retry']}")
|
|
99
|
+
print(f"线索数: {len(models.list_leads())},客户数: {len(models.list_customers())}")
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def cmd_demo_pipeline(args):
|
|
103
|
+
"""M1 销售闭环演示:01 线索雷达 → 02 跟进销冠(人工闸) → 04 成交分析 → 09 私域分层。"""
|
|
104
|
+
sched = _get_scheduler()
|
|
105
|
+
steps = [
|
|
106
|
+
{"module_id": "01", "task_type": "lead_scan",
|
|
107
|
+
"input": {"channels": ["评论区", "小红书", "公众号"], "keywords": "AI 获客"}, "priority": "P0"},
|
|
108
|
+
{"module_id": "02", "task_type": "follow_up",
|
|
109
|
+
"input": {"customer": {"company_name": "示例制造公司", "contact_name": "王总"},
|
|
110
|
+
"strategy": "标准 3 触达"}, "priority": "P0"},
|
|
111
|
+
{"module_id": "04", "task_type": "chat_analysis",
|
|
112
|
+
"input": {"transcript": "客户:价格有点高;销售:可以谈;客户:我再想想。"}, "priority": "P0"},
|
|
113
|
+
{"module_id": "09", "task_type": "tiering",
|
|
114
|
+
"input": {"customers": [
|
|
115
|
+
{"customer_id": "C1", "company_name": "示例制造公司", "contact_name": "王总", "contact_phone": "13800000001"},
|
|
116
|
+
{"customer_id": "C2", "company_name": "示例贸易公司", "contact_name": "李总", "contact_phone": "13800000002"},
|
|
117
|
+
]}, "priority": "P0"},
|
|
118
|
+
]
|
|
119
|
+
ids = sched.create_pipeline(steps)
|
|
120
|
+
print("已提交销售闭环链路:", ids)
|
|
121
|
+
sched.run_once(limit=10)
|
|
122
|
+
# 02 任务进入人工确认,演示人工闸
|
|
123
|
+
for tid in ids:
|
|
124
|
+
t = _task(tid)
|
|
125
|
+
if t and t["status"] == "awaiting_human":
|
|
126
|
+
print(f"任务 {tid} 等待人工确认 -> 自动批准")
|
|
127
|
+
sched.approve(tid, approved=True)
|
|
128
|
+
sched.run_once(limit=10)
|
|
129
|
+
_print_pipeline_summary(ids)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def _task(task_id):
|
|
133
|
+
from core import models
|
|
134
|
+
return models.get_task(task_id)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def _print_pipeline_summary(ids):
|
|
138
|
+
from core import models
|
|
139
|
+
print("\n===== 销售闭环执行结果 =====")
|
|
140
|
+
for tid in ids:
|
|
141
|
+
t = models.get_task(tid)
|
|
142
|
+
out = t.get("output_json", {})
|
|
143
|
+
brief = ""
|
|
144
|
+
if "leads" in out:
|
|
145
|
+
brief = f"线索 {out['total']} 条"
|
|
146
|
+
elif "follow_up" in out:
|
|
147
|
+
brief = f"跟进对象 {out['follow_up'].get('target', '')}"
|
|
148
|
+
elif "diagnosis" in out:
|
|
149
|
+
brief = "卡点: " + "、".join(out["diagnosis"].get("blockers", []))
|
|
150
|
+
elif "tiers" in out:
|
|
151
|
+
brief = f"分层 {len(out['tiers'])} 个客户"
|
|
152
|
+
print(f" {t['module_id']} {t['task_type']:<16} -> {t['status']:<16} {brief}")
|
|
153
|
+
print(f"\n线索库: {len(models.list_leads())} 条;客户库: {len(models.list_customers())} 条")
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def cmd_export_skills(args):
|
|
157
|
+
from skill_packager import export_skills
|
|
158
|
+
outdir = Path(args.outdir)
|
|
159
|
+
exported = export_skills(outdir)
|
|
160
|
+
print(f"已导出 {len(exported)} 个 Skill 包到 {outdir.resolve()}/")
|
|
161
|
+
for e in exported:
|
|
162
|
+
print(f" [{e['module_id']}] {e['name']} -> {e['path']}")
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def cmd_install_skills(args):
|
|
166
|
+
from skill_packager import install_skills
|
|
167
|
+
source = Path(args.source)
|
|
168
|
+
target = Path(args.target)
|
|
169
|
+
installed = install_skills(source, target)
|
|
170
|
+
print(f"已安装 {len(installed)} 个 Skill 到 {target.resolve()}/")
|
|
171
|
+
for i in installed:
|
|
172
|
+
print(f" {i['name']} -> {i['path']}")
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def build_parser():
|
|
176
|
+
p = argparse.ArgumentParser(prog="feihongzhi", description="飞虹智 · AI 员工军团系统")
|
|
177
|
+
sub = p.add_subparsers(dest="command", required=True)
|
|
178
|
+
|
|
179
|
+
sub.add_parser("init-db", help="初始化数据库")
|
|
180
|
+
sub.add_parser("list-agents", help="查看 AI 员工清单")
|
|
181
|
+
|
|
182
|
+
sp = sub.add_parser("submit", help="提交任务")
|
|
183
|
+
sp.add_argument("--module", required=True, help="模块编号 01-17")
|
|
184
|
+
sp.add_argument("--type", default="manual", help="任务类型")
|
|
185
|
+
sp.add_argument("--input", default="", help="输入 JSON")
|
|
186
|
+
sp.add_argument("--priority", default="P1", choices=["P0", "P1", "P2", "P3"])
|
|
187
|
+
sp.add_argument("--no-human-gate", action="store_true", help="关闭人工确认闸(测试用)")
|
|
188
|
+
|
|
189
|
+
rp = sub.add_parser("run-once", help="执行一轮 pending 任务")
|
|
190
|
+
rp.add_argument("--limit", type=int, default=10)
|
|
191
|
+
|
|
192
|
+
lp = sub.add_parser("run-loop", help="持续执行")
|
|
193
|
+
lp.add_argument("--times", type=int, default=3)
|
|
194
|
+
lp.add_argument("--limit", type=int, default=10)
|
|
195
|
+
|
|
196
|
+
ap = sub.add_parser("approve", help="人工确认任务")
|
|
197
|
+
ap.add_argument("--task-id", required=True)
|
|
198
|
+
ap.add_argument("--no", action="store_true", help="驳回")
|
|
199
|
+
|
|
200
|
+
sub.add_parser("stats", help="统计")
|
|
201
|
+
sub.add_parser("demo-pipeline", help="M1 销售闭环演示")
|
|
202
|
+
|
|
203
|
+
ep = sub.add_parser("export-skills", help="导出 Skill 包")
|
|
204
|
+
ep.add_argument("--outdir", default=str(BASE_DIR / "skills"))
|
|
205
|
+
|
|
206
|
+
ip = sub.add_parser("install-skills", help="安装 Skill 包")
|
|
207
|
+
ip.add_argument("--source", default=str(BASE_DIR / "skills"))
|
|
208
|
+
ip.add_argument("--target", default=str(Path.home() / ".doubao/agent_mode/workspace/.user_skills"))
|
|
209
|
+
return p
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def main(argv=None):
|
|
213
|
+
parser = build_parser()
|
|
214
|
+
args = parser.parse_args(argv)
|
|
215
|
+
dispatch = {
|
|
216
|
+
"init-db": cmd_init_db,
|
|
217
|
+
"list-agents": cmd_list_agents,
|
|
218
|
+
"submit": cmd_submit,
|
|
219
|
+
"run-once": cmd_run_once,
|
|
220
|
+
"run-loop": cmd_run_loop,
|
|
221
|
+
"approve": cmd_approve,
|
|
222
|
+
"stats": cmd_stats,
|
|
223
|
+
"demo-pipeline": cmd_demo_pipeline,
|
|
224
|
+
"export-skills": cmd_export_skills,
|
|
225
|
+
"install-skills": cmd_install_skills,
|
|
226
|
+
}
|
|
227
|
+
try:
|
|
228
|
+
dispatch[args.command](args)
|
|
229
|
+
except Exception as e: # noqa: BLE001
|
|
230
|
+
print(f"错误: {e}", file=sys.stderr)
|
|
231
|
+
sys.exit(1)
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
if __name__ == "__main__":
|
|
235
|
+
main()
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
"""Skill 打包分发器:将 17 个 AI 员工模块导出为可独立安装/调用的 Skill 包。
|
|
2
|
+
|
|
3
|
+
每个 Skill 包结构(对齐本环境 Skill 规范):
|
|
4
|
+
skills/<module_id>_<模块名>/
|
|
5
|
+
SKILL.md 供智能体发现与调用(frontmatter name/description + 使用说明)
|
|
6
|
+
run.py 自包含运行器:内嵌该模块核心逻辑,仅依赖标准库
|
|
7
|
+
|
|
8
|
+
命令:
|
|
9
|
+
python3 main.py export-skills # 导出全部模块到 skills/
|
|
10
|
+
python3 main.py install-skills # 安装到默认 Skill 根目录(.user_skills)
|
|
11
|
+
python3 main.py install-skills --target /path/to/skill_root
|
|
12
|
+
"""
|
|
13
|
+
import ast
|
|
14
|
+
import inspect
|
|
15
|
+
import json
|
|
16
|
+
import shutil
|
|
17
|
+
import sys
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
from typing import Dict, List, Optional
|
|
20
|
+
|
|
21
|
+
from agents.registry import get_agent_classes
|
|
22
|
+
from config import BASE_DIR
|
|
23
|
+
|
|
24
|
+
RUN_PY_TEMPLATE = '''#!/usr/bin/env python3
|
|
25
|
+
# -*- coding: utf-8 -*-
|
|
26
|
+
"""{name}({module_id})独立运行器。
|
|
27
|
+
|
|
28
|
+
由 feihongzhi_agents 导出:自包含、仅标准库,可被其他智能体直接调用或安装为 Skill。
|
|
29
|
+
用法:
|
|
30
|
+
python3 run.py --input '{{"field": "value"}}'
|
|
31
|
+
echo '{{"field": "value"}}' | python3 run.py
|
|
32
|
+
可选接入真实大模型(设置环境变量后加 --llm):
|
|
33
|
+
LLM_API_KEY=xxx LLM_MODEL=xxx LLM_BASE_URL=https://ark.cn-beijing.volces.com/api/v3
|
|
34
|
+
python3 run.py --llm --input '...'
|
|
35
|
+
"""
|
|
36
|
+
import argparse
|
|
37
|
+
import json
|
|
38
|
+
import sys
|
|
39
|
+
import time
|
|
40
|
+
import urllib.request
|
|
41
|
+
import urllib.error
|
|
42
|
+
from datetime import datetime
|
|
43
|
+
|
|
44
|
+
# ------------------------- 内嵌核心逻辑(自动生成) -------------------------
|
|
45
|
+
{body}
|
|
46
|
+
# ------------------------- 极简 LLM 客户端(可选) -------------------------
|
|
47
|
+
class _MiniLLM:
|
|
48
|
+
provider = "doubao"
|
|
49
|
+
def __init__(self):
|
|
50
|
+
import os
|
|
51
|
+
self.key = os.environ.get("LLM_API_KEY", "")
|
|
52
|
+
self.model = os.environ.get("LLM_MODEL", "")
|
|
53
|
+
self.base = os.environ.get("LLM_BASE_URL", "https://ark.cn-beijing.volces.com/api/v3").rstrip("/")
|
|
54
|
+
if not self.key or not self.model:
|
|
55
|
+
raise RuntimeError("缺少 LLM_API_KEY / LLM_MODEL 环境变量")
|
|
56
|
+
def complete(self, prompt, system=""):
|
|
57
|
+
msgs = []
|
|
58
|
+
if system:
|
|
59
|
+
msgs.append({{"role": "system", "content": system}})
|
|
60
|
+
msgs.append({{"role": "user", "content": prompt}})
|
|
61
|
+
payload = {{"model": self.model, "messages": msgs, "temperature": 0.7, "max_tokens": 1024}}
|
|
62
|
+
req = urllib.request.Request(
|
|
63
|
+
self.base + "/chat/completions",
|
|
64
|
+
data=json.dumps(payload).encode("utf-8"),
|
|
65
|
+
headers={{"Content-Type": "application/json", "Authorization": "Bearer " + self.key}},
|
|
66
|
+
method="POST")
|
|
67
|
+
try:
|
|
68
|
+
with urllib.request.urlopen(req, timeout=60) as resp:
|
|
69
|
+
body = json.loads(resp.read().decode("utf-8"))
|
|
70
|
+
except urllib.error.HTTPError as e:
|
|
71
|
+
raise RuntimeError("LLM 调用失败 HTTP %s: %s" % (e.code, e.read().decode("utf-8", errors="ignore")[:200]))
|
|
72
|
+
return body["choices"][0]["message"]["content"].strip()
|
|
73
|
+
|
|
74
|
+
def _load_input(args):
|
|
75
|
+
if args.input:
|
|
76
|
+
return json.loads(args.input)
|
|
77
|
+
if not sys.stdin.isatty():
|
|
78
|
+
raw = sys.stdin.read()
|
|
79
|
+
if raw.strip():
|
|
80
|
+
return json.loads(raw)
|
|
81
|
+
return {{}}
|
|
82
|
+
|
|
83
|
+
def main():
|
|
84
|
+
ap = argparse.ArgumentParser(description="{name}({module_id})")
|
|
85
|
+
ap.add_argument("--input", help="JSON 输入,如 '{{\\"topic\\": \\"AI获客\\"}}';或经 stdin 传入")
|
|
86
|
+
ap.add_argument("--llm", action="store_true", help="启用真实大模型(需 LLM_API_KEY/LLM_MODEL 环境变量)")
|
|
87
|
+
args = ap.parse_args()
|
|
88
|
+
data = _load_input(args)
|
|
89
|
+
llm = None
|
|
90
|
+
if args.llm:
|
|
91
|
+
try:
|
|
92
|
+
llm = _MiniLLM()
|
|
93
|
+
except Exception as e:
|
|
94
|
+
print(json.dumps({{"ok": False, "error": "LLM 初始化失败: " + str(e)}}, ensure_ascii=False))
|
|
95
|
+
sys.exit(1)
|
|
96
|
+
try:
|
|
97
|
+
out = {entry_func}(data, llm)
|
|
98
|
+
except Exception as e:
|
|
99
|
+
print(json.dumps({{"ok": False, "error": str(e)}}, ensure_ascii=False))
|
|
100
|
+
sys.exit(1)
|
|
101
|
+
print(json.dumps({{"ok": True, "output": out}}, ensure_ascii=False))
|
|
102
|
+
|
|
103
|
+
if __name__ == "__main__":
|
|
104
|
+
main()
|
|
105
|
+
'''
|
|
106
|
+
|
|
107
|
+
SKILL_MD_TEMPLATE = """---
|
|
108
|
+
name: {name}
|
|
109
|
+
description: {description}。属于{layer}层,优先级{priority}。触发场景:用户需要{trigger}、或涉及{inputs}相关任务时调用。输出:{outputs}。
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
# {name}({module_id})
|
|
113
|
+
|
|
114
|
+
{description}
|
|
115
|
+
|
|
116
|
+
- **所属层级**:{layer}(优先级 {priority})
|
|
117
|
+
|
|
118
|
+
## 使用方式
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
# 方式一:命令行参数
|
|
122
|
+
python3 run.py --input '{{"{ex_field}": "{ex_value}"}}'
|
|
123
|
+
|
|
124
|
+
# 方式二:标准输入
|
|
125
|
+
echo '{{"{ex_field}": "{ex_value}"}}' | python3 run.py
|
|
126
|
+
|
|
127
|
+
# 接入真实大模型(可选)
|
|
128
|
+
LLM_API_KEY=xxx LLM_MODEL=xxx python3 run.py --llm --input '{{"{ex_field}": "{ex_value}"}}'
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## 输入字段
|
|
132
|
+
|
|
133
|
+
| 字段 | 说明 |
|
|
134
|
+
|---|---|
|
|
135
|
+
{table_rows}
|
|
136
|
+
|
|
137
|
+
## 输出字段
|
|
138
|
+
|
|
139
|
+
{output_rows}
|
|
140
|
+
|
|
141
|
+
## 安装为 Skill
|
|
142
|
+
|
|
143
|
+
将本目录(含 SKILL.md 与 run.py)复制到目标 Skill 根目录即可被智能体发现调用。
|
|
144
|
+
"""
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def _collect_dependencies(func) -> Dict[str, object]:
|
|
148
|
+
"""收集函数引用的同模块顶层函数(如 _ts),供内嵌。"""
|
|
149
|
+
try:
|
|
150
|
+
tree = ast.parse(inspect.getsource(func))
|
|
151
|
+
except (OSError, TypeError):
|
|
152
|
+
return {}
|
|
153
|
+
used: set = set()
|
|
154
|
+
for node in ast.walk(tree):
|
|
155
|
+
if isinstance(node, ast.Call) and isinstance(node.func, ast.Name):
|
|
156
|
+
used.add(node.func.id)
|
|
157
|
+
elif isinstance(node, ast.Name) and isinstance(node.ctx, ast.Load):
|
|
158
|
+
used.add(node.id)
|
|
159
|
+
mod = inspect.getmodule(func)
|
|
160
|
+
deps: Dict[str, object] = {}
|
|
161
|
+
for name in used:
|
|
162
|
+
obj = getattr(mod, name, None)
|
|
163
|
+
if obj is not None and inspect.isfunction(obj) and getattr(obj, "__module__", None) == mod.__name__:
|
|
164
|
+
if name != func.__name__:
|
|
165
|
+
deps[name] = obj
|
|
166
|
+
return deps
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def _body_source(cls) -> tuple:
|
|
170
|
+
"""收集 run_logic 及其依赖函数源码,保证独立 run.py 自包含。返回 (源码, 入口函数名)。"""
|
|
171
|
+
func = cls.run_logic.__func__ if isinstance(cls.run_logic, staticmethod) else cls.run_logic
|
|
172
|
+
chunks: List[str] = []
|
|
173
|
+
seen: set = set()
|
|
174
|
+
|
|
175
|
+
def add(f):
|
|
176
|
+
if id(f) in seen:
|
|
177
|
+
return
|
|
178
|
+
seen.add(id(f))
|
|
179
|
+
for dep in _collect_dependencies(f).values():
|
|
180
|
+
add(dep)
|
|
181
|
+
chunks.append(inspect.getsource(f))
|
|
182
|
+
|
|
183
|
+
add(func)
|
|
184
|
+
return "\n\n".join(chunks), func.__name__
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def _first_key(schema: Dict[str, str]) -> tuple:
|
|
188
|
+
if not schema:
|
|
189
|
+
return ("data", "{}")
|
|
190
|
+
k = next(iter(schema))
|
|
191
|
+
if k == "customers":
|
|
192
|
+
return (k, '[{"customer_id":"C1","company_name":"客户A","contact_name":"李总"}]')
|
|
193
|
+
if k in ("channels", "target_accounts", "competitor_accounts", "hot_topics", "selling_points", "clips", "tasks"):
|
|
194
|
+
return (k, '["示例A","示例B"]')
|
|
195
|
+
if k == "transcript":
|
|
196
|
+
return (k, "客户:价格有点高;销售:可以谈。")
|
|
197
|
+
return (k, "示例输入")
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def export_skills(outdir: Path) -> List[Dict[str, str]]:
|
|
201
|
+
outdir = Path(outdir)
|
|
202
|
+
outdir.mkdir(parents=True, exist_ok=True)
|
|
203
|
+
exported: List[Dict[str, str]] = []
|
|
204
|
+
for cls in get_agent_classes():
|
|
205
|
+
agent = cls(llm=None)
|
|
206
|
+
meta = agent.meta()
|
|
207
|
+
slug = f"{meta['module_id']}_{meta['name']}"
|
|
208
|
+
pkg = outdir / slug
|
|
209
|
+
pkg.mkdir(parents=True, exist_ok=True)
|
|
210
|
+
|
|
211
|
+
body, entry_func = _body_source(cls)
|
|
212
|
+
run_py = RUN_PY_TEMPLATE.format(name=meta["name"], module_id=meta["module_id"],
|
|
213
|
+
body=body, entry_func=entry_func)
|
|
214
|
+
(pkg / "run.py").write_text(run_py, encoding="utf-8")
|
|
215
|
+
|
|
216
|
+
ex_field, ex_value = _first_key(meta["input_schema"])
|
|
217
|
+
table_rows = "\n".join(f"| {k} | {v} |" for k, v in meta["input_schema"].items()) or "| (无必填) | 可传任意 JSON |"
|
|
218
|
+
output_rows = "\n".join(f"- **{k}**:{v}" for k, v in meta["output_keys"].items()) or "- **result**:处理结果"
|
|
219
|
+
trigger = meta["name"]
|
|
220
|
+
md = SKILL_MD_TEMPLATE.format(
|
|
221
|
+
name=slug, module_id=meta["module_id"], description=meta["description"],
|
|
222
|
+
layer=meta["layer"], priority=meta["priority"], trigger=trigger,
|
|
223
|
+
inputs="、".join(meta["input_schema"].keys()) or "任意 JSON",
|
|
224
|
+
outputs="、".join(meta["output_keys"].keys()) or "result",
|
|
225
|
+
ex_field=ex_field, ex_value=ex_value,
|
|
226
|
+
table_rows=table_rows, output_rows=output_rows,
|
|
227
|
+
)
|
|
228
|
+
(pkg / "SKILL.md").write_text(md, encoding="utf-8")
|
|
229
|
+
exported.append({"module_id": meta["module_id"], "name": meta["name"], "path": str(pkg)})
|
|
230
|
+
return exported
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def install_skills(source: Path, target: Path) -> List[Dict[str, str]]:
|
|
234
|
+
source = Path(source)
|
|
235
|
+
target = Path(target)
|
|
236
|
+
target.mkdir(parents=True, exist_ok=True)
|
|
237
|
+
installed: List[Dict[str, str]] = []
|
|
238
|
+
for pkg in sorted(source.iterdir()):
|
|
239
|
+
if not pkg.is_dir():
|
|
240
|
+
continue
|
|
241
|
+
if not (pkg / "SKILL.md").exists():
|
|
242
|
+
continue
|
|
243
|
+
dest = target / pkg.name
|
|
244
|
+
if dest.exists():
|
|
245
|
+
shutil.rmtree(dest)
|
|
246
|
+
shutil.copytree(pkg, dest)
|
|
247
|
+
installed.append({"name": pkg.name, "path": str(dest)})
|
|
248
|
+
return installed
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: 01_AI获客线索雷达
|
|
3
|
+
description: 全域线索发现、清洗与入库,构建线索池。属于L1层,优先级P0。触发场景:用户需要AI获客线索雷达、或涉及channels、keywords相关任务时调用。输出:total、leads、dedup_rule。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 01_AI获客线索雷达(01)
|
|
7
|
+
|
|
8
|
+
全域线索发现、清洗与入库,构建线索池
|
|
9
|
+
|
|
10
|
+
- **所属层级**:L1(优先级 P0)
|
|
11
|
+
|
|
12
|
+
## 使用方式
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
# 方式一:命令行参数
|
|
16
|
+
python3 run.py --input '{"channels": "["示例A","示例B"]"}'
|
|
17
|
+
|
|
18
|
+
# 方式二:标准输入
|
|
19
|
+
echo '{"channels": "["示例A","示例B"]"}' | python3 run.py
|
|
20
|
+
|
|
21
|
+
# 接入真实大模型(可选)
|
|
22
|
+
LLM_API_KEY=xxx LLM_MODEL=xxx python3 run.py --llm --input '{"channels": "["示例A","示例B"]"}'
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## 输入字段
|
|
26
|
+
|
|
27
|
+
| 字段 | 说明 |
|
|
28
|
+
|---|---|
|
|
29
|
+
| channels | 线索渠道列表,如 ["评论区","小红书","公众号"] |
|
|
30
|
+
| keywords | 获客关键词 |
|
|
31
|
+
|
|
32
|
+
## 输出字段
|
|
33
|
+
|
|
34
|
+
- **total**:线索总数
|
|
35
|
+
- **leads**:线索列表
|
|
36
|
+
- **dedup_rule**:去重规则
|
|
37
|
+
|
|
38
|
+
## 安装为 Skill
|
|
39
|
+
|
|
40
|
+
将本目录(含 SKILL.md 与 run.py)复制到目标 Skill 根目录即可被智能体发现调用。
|