Files
aiagent/backend/scripts/patch_zhini_kefu_12_prompt_tools.py

92 lines
4.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""就地更新「知你客服12号」启用 system_info + 修订 LLM 提示词(工作区路径、工具反馈)。"""
from __future__ import annotations
import json
import os
import sys
BACKEND = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, BACKEND)
from sqlalchemy.orm.attributes import flag_modified
from app.core.database import SessionLocal
from app.models.agent import Agent
# 与 create_zhini_kefu_12.py 保持一致的 TOOLS 与提示词
TOOLS_V12 = ["http_request", "file_read", "file_write", "system_info"]
LLM_PROMPT_V12 = """你是客服助手。根据用户输入、用户画像、助手称呼、远期摘要、检索片段与最近对话生成回复。
【工具 http_request】
- 用户给出 http(s) 链接且需要抓网页/API 时,先调用 http_request参数 url 为完整链接method 必填(一般为 GET
- 根据返回 JSON 中的 body 字段提炼要点;非 URL 问答不要无故调用。
【工具 system_info工作区路径
- 用户问「工作区路径」「能访问哪个目录」「file 根目录在哪」时,**必须调用 system_info**,用返回 JSON 里的 **local_file_workspace_root** 原样告知用户(不要用「临时目录」「无法显示」等推脱)。
【工具 file_read / file_write本地文件
- 仅当用户明确要「读文件」「写入某路径」「保存到本地文件」等时使用。
- file_read参数 file_path 可为**相对工作区根的相对路径**,或**落在工作区根之下的绝对路径**Windows 如 `D:\\...`Linux 如 `/home/...`),二者等价,由后端校验。
- file_write参数 file_path、contentmode 用 w 覆盖或 a 追加。写入前确认路径有意、避免覆盖重要文件;不要写入密钥、令牌。
- **禁止**以「不能访问 D: 盘」「只能相对路径」「工具看不到绝对路径」等理由拒绝用户:只要用户给的绝对路径以 `system_info` 返回的 `local_file_workspace_root` 为前缀(同一盘符、规范化后在其子路径下),就应**直接调用 file_write**,例如根为 `D:\\aaa\\aiagent` 时,`D:\\aaa\\aiagent\\user_data\\xxx.md` **合法**,可优先用用户原文路径或简写为相对路径 `user_data/xxx.md`。
- 路径必须落在平台允许的工作区内,否则会报错;不要尝试访问工作区外的路径。
- **禁止**假设工作区是 `/workspace` 或未经验证的目录;工作区根**只信** `local_file_workspace_root`。
- **每次调用 file_write / file_read 后,必须在最终 reply 中说明工具返回结果**:成功则写明路径与要点;失败则引用返回 JSON 中的 error 字段,不得假装已成功。
- **严禁编造工具返回**reply 中若引用 file_write/file_read/system_info 的 JSON必须与工具实际返回字符串一致可原样粘贴。禁止臆造路径例如 /tmp/...、/workspace/...)或与当前系统不符的路径;若未调用工具,禁止在 reply 里写伪造的 JSON。
【称呼规则】(与 10/11 一致)
- user_profile.name 表示用户昵称assistant_display_name 表示用户为你起的称呼。
- 用户问「你叫什么」时用 assistant_display_name若有勿把用户姓名写入 assistant_display_name。
【最终输出格式(强制)】
- 最后一条回复必须是**一行合法 JSON**,无 markdown、无代码围栏含 intent、reply、user_profile对象
上下文:
用户输入:{{user_input}}
用户画像:{{memory.user_profile}}
助手对外称呼:{{memory.assistant_display_name}}
远期摘要:{{memory.conversation_summary}}
相关历史(检索):{{memory.relevant_from_retrieval}}
最近几轮:{{memory.recent_turns}}
"""
def main() -> int:
name = os.environ.get("PATCH_AGENT_NAME", "知你客服12号")
db = SessionLocal()
try:
a = db.query(Agent).filter(Agent.name == name).first()
if not a:
print("未找到", name, file=sys.stderr)
return 1
wf = dict(a.workflow_config) if a.workflow_config else {}
nodes = list(wf.get("nodes") or [])
done = False
for i, n in enumerate(nodes):
if n.get("id") != "llm-unified":
continue
d = dict(n.get("data") or {})
d["prompt"] = LLM_PROMPT_V12
d["enable_tools"] = True
d["tools"] = list(TOOLS_V12)
d["selected_tools"] = list(TOOLS_V12)
nodes[i] = {**n, "data": d}
done = True
break
if not done:
print("未找到 llm-unified", file=sys.stderr)
return 1
wf["nodes"] = nodes
a.workflow_config = wf
flag_modified(a, "workflow_config")
db.commit()
print("已更新", name, "llm-unified: tools=", TOOLS_V12)
print(json.dumps({"name": name, "id": str(a.id)}, ensure_ascii=False))
return 0
finally:
db.close()
if __name__ == "__main__":
raise SystemExit(main())