123 lines
5.0 KiB
Python
123 lines
5.0 KiB
Python
|
|
#!/usr/bin/env python3
|
|||
|
|
"""
|
|||
|
|
从「知你客服10号」复制为「知你客服11号」:
|
|||
|
|
- 在 llm-unified 上开启工具调用,仅启用 http_request(拉取网页/API 再总结)。
|
|||
|
|
- 提示词要求:需要访问 URL 时必须先调工具;最终对用户仍只输出一行合法 JSON(供下游 json-parse)。
|
|||
|
|
|
|||
|
|
环境变量:PLATFORM_BASE_URL、ZHINI_10_AGENT_ID(默认 10 号 ID)、登录账号密码。
|
|||
|
|
"""
|
|||
|
|
from __future__ import annotations
|
|||
|
|
|
|||
|
|
import json
|
|||
|
|
import os
|
|||
|
|
import sys
|
|||
|
|
|
|||
|
|
import requests
|
|||
|
|
|
|||
|
|
BASE = os.getenv("PLATFORM_BASE_URL", "http://127.0.0.1:8037").rstrip("/")
|
|||
|
|
SOURCE_AGENT_ID = os.getenv("ZHINI_10_AGENT_ID", "c853482b-d298-44e4-9862-c84318f71abb")
|
|||
|
|
USER = os.getenv("PLATFORM_USERNAME", "admin")
|
|||
|
|
PWD = os.getenv("PLATFORM_PASSWORD", "123456")
|
|||
|
|
|
|||
|
|
NEW_NAME = "知你客服11号"
|
|||
|
|
NEW_DESC = (
|
|||
|
|
"在知你客服10号基础上:主 LLM 开启工具调用,仅注册 http_request,"
|
|||
|
|
"可对用户给出的 http(s) 链接先抓取再摘要;"
|
|||
|
|
"提示词要求最终仍输出单行 JSON,兼容原记忆/解析链路。"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
LLM_PROMPT_V11 = """你是客服助手。根据用户输入、用户画像、助手称呼、远期摘要、检索片段与最近对话生成回复。
|
|||
|
|
|
|||
|
|
【工具 http_request(重要)】
|
|||
|
|
- 当用户给出明确的 http:// 或 https:// 链接,并希望你「看看网页讲了什么」「总结这个页面」「打开链接」等时,你必须先调用工具 http_request:参数 url 为完整链接,method 一般填 GET(调用时 method 为必填)。
|
|||
|
|
- 根据工具返回的 JSON 中的 body 字段作答:body 可能是 HTML 或 JSON 文本;请提炼要点写入最终 reply,不要谎称「无法直接访问」。
|
|||
|
|
- 若 body 过长,reply 中用简明中文摘要即可(200 字内为主)。
|
|||
|
|
- 非 URL 类普通问答不要无故调用 http_request。
|
|||
|
|
|
|||
|
|
【称呼规则】(与 10 号一致)
|
|||
|
|
- user_profile.name 仅表示「用户」昵称/姓名。
|
|||
|
|
- memory.assistant_display_name 非空时,用户问「你叫什么名字」等须用该称呼自称;勿把用户姓名写入 assistant_display_name。
|
|||
|
|
- 用户自我介绍姓名时写入 user_profile,勿写入 assistant_display_name。
|
|||
|
|
|
|||
|
|
【最终输出格式(强制)】
|
|||
|
|
- 无论你调用了几次工具,给用户的**最后一条消息内容**必须是**一行合法 JSON**,且**不要** markdown、**不要**代码围栏。
|
|||
|
|
- JSON 必须可被解析,且至少包含:intent(字符串)、reply(字符串)、user_profile(对象,无新信息可为 {})。
|
|||
|
|
- 示例:{"intent":"summarize_url","reply":"该网页主要介绍了……","user_profile":{}}
|
|||
|
|
|
|||
|
|
上下文:
|
|||
|
|
用户输入:{{user_input}}
|
|||
|
|
用户画像:{{memory.user_profile}}
|
|||
|
|
助手对外称呼:{{memory.assistant_display_name}}
|
|||
|
|
远期摘要:{{memory.conversation_summary}}
|
|||
|
|
相关历史(检索):{{memory.relevant_from_retrieval}}
|
|||
|
|
最近几轮:{{memory.recent_turns}}
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
|
|||
|
|
def _patch_llm_unified(wf: dict) -> None:
|
|||
|
|
for n in wf.get("nodes") or []:
|
|||
|
|
if n.get("id") != "llm-unified":
|
|||
|
|
continue
|
|||
|
|
d = n.setdefault("data", {})
|
|||
|
|
d["prompt"] = LLM_PROMPT_V11
|
|||
|
|
d["enable_tools"] = True
|
|||
|
|
d["tools"] = ["http_request"]
|
|||
|
|
d["selected_tools"] = ["http_request"]
|
|||
|
|
return
|
|||
|
|
print("警告: 未找到节点 llm-unified", file=sys.stderr)
|
|||
|
|
|
|||
|
|
|
|||
|
|
def main() -> int:
|
|||
|
|
r = requests.post(
|
|||
|
|
f"{BASE}/api/v1/auth/login",
|
|||
|
|
data={"username": USER, "password": PWD},
|
|||
|
|
headers={"Content-Type": "application/x-www-form-urlencoded"},
|
|||
|
|
timeout=15,
|
|||
|
|
)
|
|||
|
|
if r.status_code != 200:
|
|||
|
|
print("登录失败:", r.status_code, r.text[:500], file=sys.stderr)
|
|||
|
|
return 1
|
|||
|
|
token = r.json().get("access_token")
|
|||
|
|
if not token:
|
|||
|
|
print("无 access_token", file=sys.stderr)
|
|||
|
|
return 1
|
|||
|
|
h = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
|
|||
|
|
|
|||
|
|
dup = requests.post(
|
|||
|
|
f"{BASE}/api/v1/agents/{SOURCE_AGENT_ID}/duplicate",
|
|||
|
|
headers=h,
|
|||
|
|
json={"name": NEW_NAME},
|
|||
|
|
timeout=30,
|
|||
|
|
)
|
|||
|
|
if dup.status_code != 201:
|
|||
|
|
print("复制失败:", dup.status_code, dup.text[:800], file=sys.stderr)
|
|||
|
|
return 1
|
|||
|
|
new_id = dup.json()["id"]
|
|||
|
|
print("已创建副本:", new_id, NEW_NAME)
|
|||
|
|
|
|||
|
|
g = requests.get(f"{BASE}/api/v1/agents/{new_id}", headers=h, timeout=30)
|
|||
|
|
if g.status_code != 200:
|
|||
|
|
print("读取 Agent 失败:", g.text, file=sys.stderr)
|
|||
|
|
return 1
|
|||
|
|
agent = g.json()
|
|||
|
|
wf = agent["workflow_config"]
|
|||
|
|
_patch_llm_unified(wf)
|
|||
|
|
|
|||
|
|
up = requests.put(
|
|||
|
|
f"{BASE}/api/v1/agents/{new_id}",
|
|||
|
|
headers=h,
|
|||
|
|
json={"description": NEW_DESC, "workflow_config": wf},
|
|||
|
|
timeout=120,
|
|||
|
|
)
|
|||
|
|
if up.status_code != 200:
|
|||
|
|
print("更新失败:", up.status_code, up.text[:800], file=sys.stderr)
|
|||
|
|
return 1
|
|||
|
|
print("已开启 enable_tools + http_request,并更新提示词")
|
|||
|
|
print("Agent ID:", new_id)
|
|||
|
|
print(json.dumps({"id": new_id, "name": NEW_NAME}, ensure_ascii=False))
|
|||
|
|
return 0
|
|||
|
|
|
|||
|
|
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
raise SystemExit(main())
|